L <- 81
x <- 1:L
y <- sin(pi*x/(L+1))^2 |> sqrt() 

plot(x, y)

Вспомогательные функции

library(Rssa)
Загрузка требуемого пакета: svd
Загрузка требуемого пакета: forecast
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 

Присоединяю пакет: ‘Rssa’

Следующий объект скрыт от ‘package:stats’:

    decompose
library(signal)

Присоединяю пакет: ‘signal’

Следующий объект скрыт от ‘package:Rssa’:

    roots

Следующие объекты скрыты от ‘package:stats’:

    filter, poly
library(gsignal)
Registered S3 methods overwritten by 'gsignal':
  method         from  
  plot.grpdelay  signal
  plot.specgram  signal
  print.freqs    signal
  print.freqz    signal
  print.grpdelay signal
  print.impz     signal
  print.specgram signal

Присоединяю пакет: ‘gsignal’

Следующий объект скрыт от ‘package:signal’:

    Arma, as.Arma, as.Zpg, bartlett, bilinear, blackman, boxcar, butter, buttord, cheb1ord, chebwin, cheby1, cheby2,
    chirp, conv, decimate, ellip, ellipord, fftfilt, filter, filtfilt, fir1, fir2, flattopwin, freqs, freqs_plot,
    freqz, freqz_plot, gausswin, grpdelay, hamming, hanning, ifft, impz, interp, kaiser, kaiserord, levinson, Ma,
    medfilt1, poly, remez, resample, sftrans, sgolay, sgolayfilt, specgram, triang, unwrap, Zpg, zplane

Следующие объекты скрыты от ‘package:stats’:

    filter, gaussian, poly
source("eossa_new.R")


dftmtx <- function(n) {
  y <- stats::mvfft(diag(1, n))
  y
}

diag_averaging <- function(A){
  B <- A[nrow(A):1, ] |> Re()
  lapply(split(B, -(row(B) - col(B)) ), mean) |> as.numeric()
}

shift_vector <- function(vec) {
  last_element <- tail(vec, 1)
  vec <- vec[-length(vec)]
  shifted_vec <- c(last_element, vec)
  return(shifted_vec)
}

extend <- function(x, H){
  # Вычисление коэффициентов AR модели для дифференцированного ряда
  N <- length(x)
  p <- floor(N / 3)
  dx <- diff(x)
  # A <- ar(dx, order.max = p, method = "yule-walker")$ar
  A <- aryule(dx, p)$a
  
  # Правое расширение
  y <- x
  dy <- diff(y)
  er <- signal::filter(A, 1, dy)
  dy <- signal::filter(1, A, c(er, rep(0, H)))
  y <- y[1] + c(0, cumsum(dy))
  
  # Левое расширение
  y <- rev(y)
  dy <- diff(y)
  er <- signal::filter(A,1,dy)
  dy <- signal::filter(1,A,c(er, rep(0, H)))
  y <- y[1] + c(0, cumsum(dy))
  
  # Расширенный ряд
  xe <- rev(y)
  
  # Вывод результатов
  xe 
}

CiSSA

Подаётся на вход временной ряд, длина окна (если её нет, то она равна длине ряда + 1 пополам) и информация о том, нужно ли расширить ряд. Расширять ряд стоит при стохастическом тренде (Autoregressive extension (default). It is indicated for stationary and stochastic trend time series as well). Реализовано только Autoregressive extension.


На выходе список выдаётся список list(t_series, importance).
t_series — матрица, по столбцам которой располагаются временные ряды, отвечающие за частоты (i-1)/L, где i — номер столбца, L — длина окна.
importance — вектор, отвечающий за значимость i-ого временного ряда в разлолжении. Чем больше значение, тем больший вклад внёс i-тый временной ряд.

circulant_SSA <- function(ts, L = NULL, extend_flag = FALSE){
  time_series <- ts
  # Construct trajectory matrix
  N <- length(time_series)
  if (is.null(L)){
    L <- (N + 1)%/%2
  }
  # Проверка на расширения ряда
  if (extend_flag == FALSE){
    H <- 0
    time_series <- ts
  }
  else{
    H <- L
    time_series <- extend(ts, H)
  }
  
  X <- hankel(time_series, L)
  
  # Number of symmetric frequency pairs around 1/2
  if (L %% 2) {
    nf2 <- (L + 1) / 2 - 1
  } else {
    nf2 <- L / 2 - 1
  }
  
  # Number of frequencies <= 1/2
  nft <- nf2 + abs((L %% 2) - 2)
  
  # Decomposition
  # Estimate autocovariance     OK
  autocov <- numeric(L)
  for (m in 0:(L-1)){
    autocov[[m+1]] <- sum(time_series[1:(N-m)] * time_series[(1+m):N]) / (N-m)
  }
  
  # First row of circulant matrix
  circ_first_row <- numeric(L)
  for (m in 0:(L-1)){
    circ_first_row[[m+1]] <- (L-m)/L * autocov[[m+1]] + (m)/L * autocov[[L-m]]
  }
  
  # Build circulant matrix
  S_C <- matrix(circ_first_row, nrow = 1)
  shifted_vector <- circ_first_row
  for (i in 2:(L)) {
    shifted_vector <- shift_vector(shifted_vector)
    # S_C <- rbind(S_C, as.vector(shifted_vector))
    S_C <- rbind(as.vector(shifted_vector), S_C)
  }
  
  # Eigenvectors of circulant matrix (unitary base)
  U <- dftmtx(L)/sqrt(L)
  
  # Real eigenvectors (orthonormal base)
  U[, 1] <- Re(U[, 1])
  for (k in 1:nf2) {
    u_k <- U[, k + 1]
    U[, k + 1] <- sqrt(2) * Re(u_k)
    U[, L + 2 - (k + 1)] <- sqrt(2) * Im(u_k)
  }
  if (L %% 2 != 0) {
    U[, nft] <- Re(U[, nft])
  }
  
  # Eigenvalues of circulant matrix: estimated power spectral density
  psd <- abs(diag(t(U) %*% S_C %*% U))
  
  # Principal components
  W <- t(U) %*% X
  # Reconstruction
  # Elementary reconstructed series
  R <- matrix(0, nrow = N+2*H, ncol = L)
  for (k in 1:L) {
    R[, k] <- U[ ,k] %*% t(W[k, ]) |> diag_averaging()
  }
  
  # Grouping by frequency
  # Elementary reconstructed series by frequency
  Z <- matrix(0, nrow = N+2*H, ncol = nft)
  Z[, 1] <- R[, 1]
  # Importance of component
  imp <- numeric(nft)
  lambda_sm <- sum(psd)
  imp[1] <- psd[1]/lambda_sm
  for (k in 1:nf2) {
    Z[, k + 1] <- R[, k + 1] + R[, L + 2 - (k + 1)]
    imp[k+1] <- (psd[k+1] + psd[ L + 2 - (k + 1)])/lambda_sm
  }
  if (L %% 2 != 0) {
    Z[, nft] <- R[, nft]
    imp[nft] <- psd[nft] / lambda_sm
  }
  
  list(t_series = Z[(H+1):(N+H),],
       importance = imp,
       freq = (0:(length(imp) -1))/L
       )
}
# groups - list of frequencies
grouping_cissa <- function(cissa_res, groups){
  freq <- cissa_res$freq
  t_series <- cissa_res$t_series
  
  
  residuals <- 0
  result <- setNames(as.list(rep(0, length(groups))), names(groups))
  result_freqs <- list()
  for (i in 1:length(cissa_res$freq)){
    flag <- FALSE
    for (name in names(groups)){
      if (groups[[name]][1] <= freq[i] & freq[i] <= groups[[name]][2]){
        flag <- TRUE
        result[[name]] <- result[[name]] + t_series[, i]
        result_freqs[[name]] <- c(result_freqs[[name]], freq[i])
      }
    }
    
    if (flag == FALSE){
      residuals <- residuals + t_series[, i]
    }
  }
  
  result[["residuals"]] <- residuals
  
  return(
    list(
      t_series = result,
      freqs_by_group = result_freqs
    )
  )
  result
}
generate_ts <- function(func, n=1e3, ...){
  1:n |> func(...) |> ts()
}

f_cos <- function(x, A = 1, omega = 1/4, phi = 0){
  f_exp_mod_harm_series(x, A, alpha = 0, omega = omega, phi = phi)
}

f_sin <- function(x, A = 1, omega = 1/4, phi = 3*pi/2){
  f_exp_mod_harm_series(x, A, alpha = 0, omega = omega, phi = phi)
}

f_exp <- function(x, A = 1, alpha = 1){
  A * exp(alpha * x)
}

f_exp_cos <- function(x, A = 1, alpha = 1, omega = 1/4, phi = 0){
  f_exp_mod_harm_series(x, A, alpha, omega, phi)
}

f_const <- function(x, C = 0){
  rep(C, length(x))
}

f_exp_mod_harm_series <- function(x, A = 1, alpha = 1, omega = 1/4, phi = 0){
  A*exp(alpha*x)*cos(2*pi*omega*x + phi)
}

f_linear <- function(x, a = 1, b = 0){
  a*x + b
}
mse <- function(f_true, f_reconstructed){
   mean((f_true - f_reconstructed)^2) 
}

Ошибка при Lw in N, Kw not in N

n <- 96*2+5
L <- 96
eps <- 1/97
f_sum <- function(x){
  f_const(x, C = 1) + f_cos(x, omega = 1/12) 
}


f_const |> generate_ts(n, C = 1) |>
  plot(col = "green", ylim = c(-1, 2), ylab = "f_n")
f_cos |>
  generate_ts(n, omega = 1/12) |>
  lines(col="green")
f_sum |> generate_ts(n) |> lines(lwd = 3, col='red')
f_n <- f_sum(1:n)



c <- circulant_SSA(f_n, L = 96, extend_flag = FALSE)
r <- grouping_cissa(c,
               groups = list(
                 trend = c(0, eps),
                 sesonal = c(1/12-eps, 1/12 + eps)
               )
               )$t_series

f_C <- f_const |> generate_ts(n, C = 1)
f_c <- f_cos |> generate_ts(n, omega = 1/12)
print("Ошибки при CiSSA")
[1] "Ошибки при CiSSA"
print(paste("Ошибка при вычислении C = 1: ", mse(f_C, r$trend) |> format(scientific = TRUE, digits = 2) ))
[1] "Ошибка при вычислении C = 1:  3.2e-31"
print(paste("Ошибка при вычислении cos(pi/12): ", mse(f_c, r$sesonal) |> format(scientific = TRUE, digits = 2) ))
[1] "Ошибка при вычислении cos(pi/12):  5.1e-30"
lines(1:n, r$trend, col="blue")
lines(1:n, r$sesonal, col="blue")


f_const |> generate_ts(n, C = 1) |>
  plot(col = "green", ylim = c(-1, 2), ylab = "f_n")
f_cos |>
  generate_ts(n, omega = 1/12) |>
  lines(col="green")
f_sum |> generate_ts(n) |> lines(lwd = 3, col='red')
f_n <- f_sum(1:n)

s <- ssa(f_n, L = 96)
r <- reconstruct(s, groups=list(
  trend = 1,
  sesonal = 2:3
))


print("Ошибки при SSA")
[1] "Ошибки при SSA"
print(paste("Ошибка при вычислении C = 1: ", mse(f_C, r$trend) |> format(scientific = TRUE, digits = 2)  ))
[1] "Ошибка при вычислении C = 1:  9.6e-05"
print(paste("Ошибка при вычислении cos(pi/12): ", mse(f_c, r$sesonal) |> format(scientific = TRUE, digits = 2)))
[1] "Ошибка при вычислении cos(pi/12):  9.6e-05"
lines(1:n, r$trend)
lines(1:n, r$sesonal)

Проверка разделимости непериодических компонент + автогруппировка SSA

n <- 96*2-1
L <- 96
eps <- 1/97

C <- 1
omega_cs <- 1/12
omega_sn <- 1/24
a <- 1/100
f_sum <- function(x){
  f_const(x, C = C) +
    f_cos(x, omega = omega_cs) +
    f_exp(x, a = a) +
    f_sin(x, omega = omega_sn)
}


f_C <- f_const |> generate_ts(n, C = C)
f_c <- f_cos |> generate_ts(n, omega = omega_cs)
f_s <- f_sin |> generate_ts(n, omega = omega_sn)
f_e <- f_exp |> generate_ts(n, a = a)

f_n <- f_sum(1:n)

library(xtable)
Предупреждение: пакет ‘xtable’ был собран под R версии 4.2.3
# Шаг 2: Создание примера данных
data <- data.frame(
  Метод = c("SSA", "CiSSA"),
  e_err = c(20, 20),
  c_err = c(23, 35),
  ec_err = c(20, 20),
  sin_err = c (20, 20),
  cos_err = c(1, 1)
)


# Отрисовка ряда f_n
plot(f_n, type = "l", lwd = 3, col = 'red', ylim = c(-2, 10),
     xlab = "Время", ylab = "Значения ряда", main = "Разложение временного ряда")

# Добавление отдельных компонентов (f_C, f_c, f_e)
lines(f_C, col = "blue")  # Компонент f_C
lines(f_c, col = "blue")  # Компонент f_c
lines(f_e, col = "blue")  # Компонент f_e
lines(f_s, col = "blue")

# Легенда
legend("topleft", legend = c("Весь ряд", "Компоненты"), 
       col = c("red", "blue"), lty = 1, lwd = 3)









c <- circulant_SSA(f_n, L = L, extend_flag = TRUE)
# r <- c$t_series
r <- grouping_cissa(c,
                    groups = list(
                      # trend = c(0, 1/100),
                      trend = c(0, eps),
                      sesonal_cos = c(1/12-eps, 1/12+eps),
                      sesonal_sin = c(1/24 - eps, 1/24+eps)
                    ))$t_series

data$cos_err[2] <- mse(f_s, r$sesonal_sin) |> formatC(format = "e", digits = 1)
data$sin_err[2] <- mse(f_c, r$sesonal_cos) |> formatC(format = "e", digits = 1)
data$ec_err[2] <- mse(f_C+f_e, r$trend) |> formatC(format = "e", digits = 1)


# png("C:/Users/nik1m/Desktop/уник/6 сем/курсач/Текст работы/img/trend inseparability/CiSSA.png")  # сохранение в формате PNG

plot(1:n, f_n, type = "l", lwd=3, ylim= c(-2, 10), col="red",
     xlab = "Время", ylab = "Значения ряда", main = "CiSSA разложение временного ряда")
lines(1:n, r$trend, col = "blue")
lines(1:n, r$sesonal_sin, col = "blue")
lines(1:n, r$sesonal_cos, col = "blue")

# Легенда
legend("topleft", legend = c("Весь ряд", "Компоненты"), 
       col = c("red", "blue"), lty = 1, lwd = 3)


# dev.off()  # завершение сохранения










s <- ssa(f_n, L)
# e <- eossa_new(s, nested.groups = list(1:30), clust_type = "distance")
e <- eossa(s, 1:10, k = 7)

g_sesonal <- grouping.auto(e, base = "eigen",
                   freq.bins = list(trend = c(eps),
                                    sesonal2 = c(1/24-eps, 1/24+eps),
                                    sesonal1 = c(1/12-eps, 1/12+eps)
                                    ),
                   threshold = 0.1)


r <- Rssa::reconstruct(e, groups=c(list(exp = 1,
                                C = 2
                                ),
                             g_sesonal)
                 )

plot(wcor(e, groups = 1:24), scales = list(at = c(10, 20, 30)))
Предупреждение в wcor.ossa(e, groups = 1:24) :
  Component matrices are not F-orthogonal (max F-cor is 0.93). W-cor matrix can be irrelevant

data$c_err[1] <- mse(f_C, r$C) |> formatC(format = "e", digits = 1)
data$e_err[1] <- mse(f_e, r$exp) |> formatC(format = "e", digits = 1)
data$cos_err[1] <- mse(f_c, r$sesonal1) |> formatC(format = "e", digits = 1)
data$sin_err[1] <- mse(f_s, r$sesonal2) |> formatC(format = "e", digits = 1)
data$ec_err[1] <- mse(f_C+f_e, r$C+r$exp) |> formatC(format = "e", digits = 1)


# png("C:/Users/nik1m/Desktop/уник/6 сем/курсач/Текст работы/img/trend inseparability/SSA.png")  # сохранение в формате PNG

plot(1:n, f_n, type = "l", lwd=3, ylim= c(-2, 10), col="red",
     xlab = "Время", ylab = "Значения ряда", main = "SSA разложение временного ряда")

lines(1:n, r$trend, type = "l", col="green")
lines(1:n, r$exp, type = "l", ylim= c(-2, 10), col="blue")
lines(1:n, r$C, col = "blue")
lines(1:n, r$sesonal1, col = "blue")
lines(1:n, r$sesonal2, col = "blue")

# Легенда
legend("topleft", legend = c("Весь ряд", "Компоненты"), 
       col = c("red", "blue"), lty = 1, lwd = 3)








# Шаг 3: Преобразование данных в формат LaTeX
table_latex <- xtable(data, caption = "Example Table")

# Шаг 4: Вывод таблицы в LaTeX файл
print(table_latex, include.rownames = FALSE)
% latex table generated in R 4.2.2 by xtable 1.8-4 package
% Thu Nov 28 18:25:06 2024
\begin{table}[ht]
\centering
\begin{tabular}{llllll}
  \hline
Метод & e\_err & c\_err & ec\_err & sin\_err & cos\_err \\ 
  \hline
SSA & 2.2e-25 & 2.2e-25 & 4.2e-28 & 3.8e-29 & 1.6e-29 \\ 
  CiSSA & 20 & 35 & 3.5e-02 & 7.7e-04 & 1.9e-03 \\ 
   \hline
\end{tabular}
\caption{Example Table} 
\end{table}

Пример cos*exp

n <- 96*2-1
L <- 96
eps <- 1/(L+1)

C <- 1
omega_cs <- 1/12
omega_sn <- 1/24
a <- 1/100
omega_exp <- 1/48
f_sum <- function(x){
    f_cos(x, omega = omega_cs) +
    f_exp_mod_harm_series(x, a = a, omega = omega_exp) +
    f_sin(x, omega = omega_sn) 
}


f_c <- f_cos |> generate_ts(n, omega = omega_cs)
f_s <- f_sin |> generate_ts(n, omega = omega_sn)
f_e <- f_exp_mod_harm_series |> generate_ts(n, a = a, omega = omega_exp)

f_n <- f_sum(1:n)

library(xtable)

# Шаг 2: Создание примера данных
data <- data.frame(
  Метод = c("SSA", "CiSSA"),
  exp_err = c(20, 20),
  sin_err = c (20, 20),
  cos_err = c(1, 1)
)


# Отрисовка ряда f_n
plot(f_n, type = "l", lwd = 3, col = 'red', ylim = c(-10, 10),
     xlab = "Время", ylab = "Значения ряда", main = "Разложение временного ряда")

# Добавление отдельных компонентов (f_C, f_c, f_e)
lines(f_c, col = "blue")  # Компонент f_c
lines(f_e, col = "blue")  # Компонент f_e
lines(f_s, col = "blue")

# Легенда
legend("topleft", legend = c("Весь ряд", "Компоненты"), 
       col = c("red", "blue"), lty = 1, lwd = 3)









c <- circulant_SSA(f_n, L = L, extend_flag = TRUE)
# r <- c$t_series
r <- grouping_cissa(c,
                    groups = list(
                      trend = c(0, 1/26-eps),
                      sesonal_cos = c(1/12-eps, 1/12+eps),
                      sesonal_sin = c(1/24-eps, 1/24+eps)
                    ))$t_series

data$cos_err[2] <- mse(f_s, r$sesonal_sin) |> formatC(format = "e", digits = 1)
data$sin_err[2] <- mse(f_c, r$sesonal_cos) |> formatC(format = "e", digits = 1)
data$exp_err[2] <- mse(f_e, r$trend) |> formatC(format = "e", digits = 1)


# png("C:/Users/nik1m/Desktop/уник/6 сем/курсач/Текст работы/img/trend inseparability/CiSSA.png")  # сохранение в формате PNG

plot(1:n, f_n, type = "l", lwd=3, ylim= c(-10, 10), col="red",
     xlab = "Время", ylab = "Значения ряда", main = "CiSSA разложение временного ряда")
lines(1:n, r$trend, col = "blue")
lines(1:n, r$sesonal_sin, col = "blue")
lines(1:n, r$sesonal_cos, col = "blue")

# Легенда
legend("topleft", legend = c("Весь ряд", "Компоненты"), 
       col = c("red", "blue"), lty = 1, lwd = 3)


# dev.off()  # завершение сохранения










s <- ssa(f_n, L)
e <- eossa_new(s, nested.groups = list(1:30), clust_type = "distance")

g_sesonal <- grouping.auto(e, base = "eigen",
                   freq.bins = list(trend = c(1/25-eps),
                                    sesonal2 = c(1/24-eps, 1/24+eps),
                                    sesonal1 = c(1/12-eps, 1/12+eps)
                                    ),
                   threshold = 0.1)


r <- reconstruct(e, groups= g_sesonal)

plot(wcor(e, groups = 1:24), scales = list(at = c(10, 20, 30)))
Предупреждение в wcor.ossa(e, groups = 1:24) :
  Component matrices are not F-orthogonal (max F-cor is -0.529). W-cor matrix can be irrelevant

data$exp_err[1] <- mse(f_e, r$trend)  |> formatC(format = "e", digits = 1)
data$cos_err[1] <- mse(f_c, r$sesonal1) |> formatC(format = "e", digits = 1)
data$sin_err[1] <- mse(f_s, r$sesonal2) |> formatC(format = "e", digits = 1)


# png("C:/Users/nik1m/Desktop/уник/6 сем/курсач/Текст работы/img/trend inseparability/SSA.png")  # сохранение в формате PNG

plot(1:n, f_n, type = "l", lwd=3, ylim= c(-10, 10), col="red",
     xlab = "Время", ylab = "Значения ряда", main = "SSA разложение временного ряда")

lines(1:n, r$trend, type = "l", col="blue")
lines(1:n, r$sesonal1, col = "blue")
lines(1:n, r$sesonal2, col = "blue")

# Легенда
legend("topleft", legend = c("Весь ряд", "Компоненты"), 
       col = c("red", "blue"), lty = 1, lwd = 3)








# Шаг 3: Преобразование данных в формат LaTeX
table_latex <- xtable(data, caption = "Example Table")

# Шаг 4: Вывод таблицы в LaTeX файл
print(table_latex, include.rownames = FALSE)
% latex table generated in R 4.2.2 by xtable 1.8-4 package
% Thu Nov 28 18:25:07 2024
\begin{table}[ht]
\centering
\begin{tabular}{llll}
  \hline
Метод & exp\_err & sin\_err & cos\_err \\ 
  \hline
SSA & 4.7e-29 & 1.1e-29 & 8.4e-30 \\ 
  CiSSA & 3.2e-02 & 1.0e-03 & 5.8e-03 \\ 
   \hline
\end{tabular}
\caption{Example Table} 
\end{table}

Данные IP

library(readxl)
Предупреждение: пакет ‘readxl’ был собран под R версии 4.2.3
data <- read_excel("Data/International_Financial_Statistics_.xlsx")
New names:
• `` -> `...2`
• `` -> `...3`
• `` -> `...4`
• `` -> `...5`
• `` -> `...6`
• `` -> `...7`
• `` -> `...8`
• `` -> `...9`
• `` -> `...10`
• `` -> `...11`
• `` -> `...12`
• `` -> `...13`
• `` -> `...14`
• `` -> `...15`
• `` -> `...16`
• `` -> `...17`
• `` -> `...18`
• `` -> `...19`
• `` -> `...20`
• `` -> `...21`
• `` -> `...22`
• `` -> `...23`
• `` -> `...24`
• `` -> `...25`
• `` -> `...26`
• `` -> `...27`
• `` -> `...28`
• `` -> `...29`
• `` -> `...30`
• `` -> `...31`
• `` -> `...32`
• `` -> `...33`
• `` -> `...34`
• `` -> `...35`
• `` -> `...36`
• `` -> `...37`
• `` -> `...38`
• `` -> `...39`
• `` -> `...40`
• `` -> `...41`
• `` -> `...42`
• `` -> `...43`
• `` -> `...44`
• `` -> `...45`
• `` -> `...46`
• `` -> `...47`
• `` -> `...48`
• `` -> `...49`
• `` -> `...50`
• `` -> `...51`
• `` -> `...52`
• `` -> `...53`
• `` -> `...54`
• `` -> `...55`
• `` -> `...56`
• `` -> `...57`
• `` -> `...58`
• `` -> `...59`
• `` -> `...60`
• `` -> `...61`
• `` -> `...62`
• `` -> `...63`
• `` -> `...64`
• `` -> `...65`
• `` -> `...66`
• `` -> `...67`
• `` -> `...68`
• `` -> `...69`
• `` -> `...70`
• `` -> `...71`
• `` -> `...72`
• `` -> `...73`
• `` -> `...74`
• `` -> `...75`
• `` -> `...76`
• `` -> `...77`
• `` -> `...78`
• `` -> `...79`
• `` -> `...80`
• `` -> `...81`
• `` -> `...82`
• `` -> `...83`
• `` -> `...84`
• `` -> `...85`
• `` -> `...86`
• `` -> `...87`
• `` -> `...88`
• `` -> `...89`
• `` -> `...90`
• `` -> `...91`
• `` -> `...92`
• `` -> `...93`
• `` -> `...94`
• `` -> `...95`
• `` -> `...96`
• `` -> `...97`
• `` -> `...98`
• `` -> `...99`
• `` -> `...100`
• `` -> `...101`
• `` -> `...102`
• `` -> `...103`
• `` -> `...104`
• `` -> `...105`
• `` -> `...106`
• `` -> `...107`
• `` -> `...108`
• `` -> `...109`
• `` -> `...110`
• `` -> `...111`
• `` -> `...112`
• `` -> `...113`
• `` -> `...114`
• `` -> `...115`
• `` -> `...116`
• `` -> `...117`
• `` -> `...118`
• `` -> `...119`
• `` -> `...120`
• `` -> `...121`
• `` -> `...122`
• `` -> `...123`
• `` -> `...124`
• `` -> `...125`
• `` -> `...126`
• `` -> `...127`
• `` -> `...128`
• `` -> `...129`
• `` -> `...130`
• `` -> `...131`
• `` -> `...132`
• `` -> `...133`
• `` -> `...134`
• `` -> `...135`
• `` -> `...136`
• `` -> `...137`
• `` -> `...138`
• `` -> `...139`
• `` -> `...140`
• `` -> `...141`
• `` -> `...142`
• `` -> `...143`
• `` -> `...144`
• `` -> `...145`
• `` -> `...146`
• `` -> `...147`
• `` -> `...148`
• `` -> `...149`
• `` -> `...150`
• `` -> `...151`
• `` -> `...152`
• `` -> `...153`
• `` -> `...154`
• `` -> `...155`
• `` -> `...156`
• `` -> `...157`
• `` -> `...158`
• `` -> `...159`
• `` -> `...160`
• `` -> `...161`
• `` -> `...162`
• `` -> `...163`
• `` -> `...164`
• `` -> `...165`
• `` -> `...166`
• `` -> `...167`
• `` -> `...168`
• `` -> `...169`
• `` -> `...170`
• `` -> `...171`
• `` -> `...172`
• `` -> `...173`
• `` -> `...174`
• `` -> `...175`
• `` -> `...176`
• `` -> `...177`
• `` -> `...178`
• `` -> `...179`
• `` -> `...180`
• `` -> `...181`
• `` -> `...182`
• `` -> `...183`
• `` -> `...184`
• `` -> `...185`
• `` -> `...186`
• `` -> `...187`
• `` -> `...188`
• `` -> `...189`
• `` -> `...190`
• `` -> `...191`
• `` -> `...192`
• `` -> `...193`
• `` -> `...194`
• `` -> `...195`
• `` -> `...196`
• `` -> `...197`
• `` -> `...198`
• `` -> `...199`
• `` -> `...200`
• `` -> `...201`
• `` -> `...202`
• `` -> `...203`
• `` -> `...204`
• `` -> `...205`
• `` -> `...206`
• `` -> `...207`
• `` -> `...208`
• `` -> `...209`
• `` -> `...210`
• `` -> `...211`
• `` -> `...212`
• `` -> `...213`
• `` -> `...214`
• `` -> `...215`
• `` -> `...216`
• `` -> `...217`
• `` -> `...218`
• `` -> `...219`
• `` -> `...220`
• `` -> `...221`
• `` -> `...222`
• `` -> `...223`
• `` -> `...224`
• `` -> `...225`
• `` -> `...226`
• `` -> `...227`
• `` -> `...228`
• `` -> `...229`
• `` -> `...230`
• `` -> `...231`
• `` -> `...232`
• `` -> `...233`
• `` -> `...234`
• `` -> `...235`
• `` -> `...236`
• `` -> `...237`
• `` -> `...238`
• `` -> `...239`
• `` -> `...240`
• `` -> `...241`
• `` -> `...242`
• `` -> `...243`
• `` -> `...244`
• `` -> `...245`
• `` -> `...246`
• `` -> `...247`
• `` -> `...248`
• `` -> `...249`
• `` -> `...250`
• `` -> `...251`
• `` -> `...252`
• `` -> `...253`
• `` -> `...254`
• `` -> `...255`
• `` -> `...256`
• `` -> `...257`
• `` -> `...258`
• `` -> `...259`
• `` -> `...260`
• `` -> `...261`
• `` -> `...262`
• `` -> `...263`
• `` -> `...264`
• `` -> `...265`
• `` -> `...266`
• `` -> `...267`
• `` -> `...268`
• `` -> `...269`
• `` -> `...270`
• `` -> `...271`
• `` -> `...272`
• `` -> `...273`
• `` -> `...274`
• `` -> `...275`
• `` -> `...276`
• `` -> `...277`
• `` -> `...278`
• `` -> `...279`
• `` -> `...280`
• `` -> `...281`
• `` -> `...282`
• `` -> `...283`
• `` -> `...284`
• `` -> `...285`
• `` -> `...286`
• `` -> `...287`
• `` -> `...288`
• `` -> `...289`
• `` -> `...290`
• `` -> `...291`
• `` -> `...292`
• `` -> `...293`
• `` -> `...294`
• `` -> `...295`
• `` -> `...296`
• `` -> `...297`
• `` -> `...298`
• `` -> `...299`
• `` -> `...300`
• `` -> `...301`
• `` -> `...302`
• `` -> `...303`
• `` -> `...304`
• `` -> `...305`
• `` -> `...306`
• `` -> `...307`
• `` -> `...308`
• `` -> `...309`
• `` -> `...310`
• `` -> `...311`
• `` -> `...312`
• `` -> `...313`
• `` -> `...314`
• `` -> `...315`
• `` -> `...316`
• `` -> `...317`
• `` -> `...318`
• `` -> `...319`
• `` -> `...320`
• `` -> `...321`
• `` -> `...322`
• `` -> `...323`
• `` -> `...324`
• `` -> `...325`
• `` -> `...326`
• `` -> `...327`
• `` -> `...328`
• `` -> `...329`
• `` -> `...330`
• `` -> `...331`
• `` -> `...332`
• `` -> `...333`
• `` -> `...334`
• `` -> `...335`
• `` -> `...336`
• `` -> `...337`
• `` -> `...338`
• `` -> `...339`
• `` -> `...340`
• `` -> `...341`
• `` -> `...342`
• `` -> `...343`
• `` -> `...344`
• `` -> `...345`
• `` -> `...346`
• `` -> `...347`
• `` -> `...348`
• `` -> `...349`
• `` -> `...350`
• `` -> `...351`
• `` -> `...352`
• `` -> `...353`
• `` -> `...354`
• `` -> `...355`
• `` -> `...356`
• `` -> `...357`
• `` -> `...358`
• `` -> `...359`
• `` -> `...360`
• `` -> `...361`
• `` -> `...362`
• `` -> `...363`
• `` -> `...364`
• `` -> `...365`
• `` -> `...366`
• `` -> `...367`
• `` -> `...368`
• `` -> `...369`
• `` -> `...370`
• `` -> `...371`
• `` -> `...372`
• `` -> `...373`
• `` -> `...374`
• `` -> `...375`
• `` -> `...376`
• `` -> `...377`
• `` -> `...378`
• `` -> `...379`
• `` -> `...380`
• `` -> `...381`
• `` -> `...382`
• `` -> `...383`
• `` -> `...384`
• `` -> `...385`
• `` -> `...386`
• `` -> `...387`
• `` -> `...388`
• `` -> `...389`
• `` -> `...390`
• `` -> `...391`
• `` -> `...392`
• `` -> `...393`
• `` -> `...394`
• `` -> `...395`
• `` -> `...396`
• `` -> `...397`
• `` -> `...398`
• `` -> `...399`
• `` -> `...400`
• `` -> `...401`
• `` -> `...402`
• `` -> `...403`
• `` -> `...404`
• `` -> `...405`
• `` -> `...406`
• `` -> `...407`
• `` -> `...408`
• `` -> `...409`
• `` -> `...410`
• `` -> `...411`
• `` -> `...412`
• `` -> `...413`
• `` -> `...414`
• `` -> `...415`
• `` -> `...416`
• `` -> `...417`
• `` -> `...418`
• `` -> `...419`
• `` -> `...420`
• `` -> `...421`
• `` -> `...422`
• `` -> `...423`
• `` -> `...424`
• `` -> `...425`
• `` -> `...426`
• `` -> `...427`
• `` -> `...428`
• `` -> `...429`
• `` -> `...430`
• `` -> `...431`
• `` -> `...432`
• `` -> `...433`
• `` -> `...434`
• `` -> `...435`
• `` -> `...436`
• `` -> `...437`
• `` -> `...438`
• `` -> `...439`
• `` -> `...440`
• `` -> `...441`
• `` -> `...442`
• `` -> `...443`
• `` -> `...444`
• `` -> `...445`
• `` -> `...446`
• `` -> `...447`
• `` -> `...448`
• `` -> `...449`
• `` -> `...450`
• `` -> `...451`
• `` -> `...452`
• `` -> `...453`
• `` -> `...454`
• `` -> `...455`
• `` -> `...456`
• `` -> `...457`
• `` -> `...458`
• `` -> `...459`
• `` -> `...460`
• `` -> `...461`
• `` -> `...462`
• `` -> `...463`
• `` -> `...464`
• `` -> `...465`
• `` -> `...466`
• `` -> `...467`
• `` -> `...468`
• `` -> `...469`
• `` -> `...470`
• `` -> `...471`
• `` -> `...472`
• `` -> `...473`
• `` -> `...474`
• `` -> `...475`
• `` -> `...476`
• `` -> `...477`
• `` -> `...478`
• `` -> `...479`
• `` -> `...480`
• `` -> `...481`
• `` -> `...482`
• `` -> `...483`
• `` -> `...484`
• `` -> `...485`
• `` -> `...486`
• `` -> `...487`
• `` -> `...488`
• `` -> `...489`
• `` -> `...490`
• `` -> `...491`
• `` -> `...492`
• `` -> `...493`
• `` -> `...494`
• `` -> `...495`
• `` -> `...496`
• `` -> `...497`
• `` -> `...498`
• `` -> `...499`
• `` -> `...500`
• `` -> `...501`
• `` -> `...502`
• `` -> `...503`
• `` -> `...504`
• `` -> `...505`
• `` -> `...506`
• `` -> `...507`
• `` -> `...508`
• `` -> `...509`
• `` -> `...510`
• `` -> `...511`
• `` -> `...512`
• `` -> `...513`
• `` -> `...514`
• `` -> `...515`
• `` -> `...516`
• `` -> `...517`
• `` -> `...518`
• `` -> `...519`
• `` -> `...520`
• `` -> `...521`
• `` -> `...522`
• `` -> `...523`
• `` -> `...524`
• `` -> `...525`
• `` -> `...526`
• `` -> `...527`
• `` -> `...528`
• `` -> `...529`
• `` -> `...530`
• `` -> `...531`
• `` -> `...532`
• `` -> `...533`
• `` -> `...534`
• `` -> `...535`
• `` -> `...536`
• `` -> `...537`
• `` -> `...538`
• `` -> `...539`
• `` -> `...540`
• `` -> `...541`
• `` -> `...542`
• `` -> `...543`
• `` -> `...544`
• `` -> `...545`
• `` -> `...546`
• `` -> `...547`
• `` -> `...548`
• `` -> `...549`
• `` -> `...550`
• `` -> `...551`
• `` -> `...552`
• `` -> `...553`
• `` -> `...554`
• `` -> `...555`
• `` -> `...556`
• `` -> `...557`
• `` -> `...558`
• `` -> `...559`
• `` -> `...560`
• `` -> `...561`
• `` -> `...562`
• `` -> `...563`
• `` -> `...564`
• `` -> `...565`
• `` -> `...566`
• `` -> `...567`
• `` -> `...568`
• `` -> `...569`
• `` -> `...570`
• `` -> `...571`
• `` -> `...572`
• `` -> `...573`
• `` -> `...574`
• `` -> `...575`
• `` -> `...576`
• `` -> `...577`
• `` -> `...578`
• `` -> `...579`
data |> head()

Отрисовка данных IP

dates <- seq(as.Date("1970-01-01"), as.Date("2018-1-30"), by = "month")
IP_values <- data[2, -c(1, 2)] |> as.double() 
plot(dates, IP_values, type="l")

Cissa

Отрисовка трендовой составляющей чёрным цветом, основной временной ряд — красным

data_slice <- 1:537
dates_slice <- dates[data_slice]
IP_values_slice <- IP_values[data_slice]
eps <- 1/193

c <- circulant_SSA(IP_values_slice, L = 192, extend_flag = TRUE)
r <- c$t_series
r <- grouping_cissa(c,
                    groups = list(
                      trend = c(0, 1/192),
                      cycle = c(1/97, 5/95),
                      sesonal = c(1/13, 1/2+0.0001)
                    )
                    )$t_series
r_sesonal <-  grouping_cissa(c,
                             groups = list(
                              s1 = c(16/192 - eps, 16/192 + eps),
                              s2 = c(32/192 - eps, 32/192 + eps),
                              s3 = c(48/192 - eps, 48/192 + eps),
                              s4 = c(64/192 - eps, 64/192 + eps),
                              s5 = c(80/192 - eps, 80/192 + eps),
                              s6 = c(96/192 - eps, 96/192 + eps)
                             )
                             )$t_series
# cissa_trend <- r[,1] + r[,2]
# cissa_cycle <- r[, 3:11] |> rowSums()
# cissa_sesonal <- r[, c(17, 33, 49, 65, 81, 97)] |> rowSums()
# cissa_residuals <- IP_values_slice - (cissa_trend + cissa_cycle + cissa_sesonal)

cissa_trend <- r$trend
cissa_cycle <- r$cycle
cissa_sesonal <- Reduce("+", r_sesonal |> within(rm(residuals)))
cissa_residuals <- IP_values_slice - (cissa_trend + cissa_cycle + cissa_sesonal)


plot(dates_slice, IP_values_slice,
     type="l", col = "black")
lines(dates_slice, cissa_trend,
      type="l", col = "red")


plot(dates_slice, cissa_cycle,
     type="l", col = "red")


plot(dates_slice, cissa_sesonal,
     type="l", col = "red")


plot(dates_slice, cissa_residuals,
     type="l", col = "red")


plot(dates_slice, IP_values_slice,
     type="l", col = "black")
lines(dates_slice, cissa_trend+cissa_cycle+cissa_sesonal,
      type="l", col = "red")

SSA fossa

s <- ssa(IP_values_slice, L = 192)
e <- fossa(s)
# e <- eossa_new(s, nested.groups = list(1:30), clust_type = "distance")
eps <- 1/193

groups <- grouping.auto(e,
                   freq.bins = list(trend = c(1/192),
                                    cycle = c(1/97, 5/95),
                                    s1 = c(16/192 - eps, 16/192 + eps),
                                    s2 = c(32/192 - eps, 32/192 + eps),
                                    s3 = c(48/192 - eps, 48/192 + eps),
                                    s4 = c(64/192 - eps, 64/192 + eps),
                                    s5 = c(80/192 - eps, 80/192 + eps),
                                    s6 = c(96/192 - eps, 96/192 + eps)
                                    ),
                   threshold = 0)


plot(wcor(e, groups = 1:30), scales = list(at = c(10, 20, 30)),
     main = "W-correlation matrix SSA (fossa)")


r <- reconstruct(e, groups=groups)

ssa_trend_f <- r$trend
ssa_cycle_f <- r$cycle
ssa_sesonal_f <- r$s1 + r$s2 + r$s3 + r$s4 + r$s5 + r$s6
ssa_residuals_f <- IP_values_slice - (ssa_trend_f + ssa_cycle_f + ssa_sesonal_f)

plot(dates_slice, IP_values_slice,
     type="l", col = "black")
lines(dates_slice, ssa_trend_f,
      type="l", col = "magenta")


plot(dates_slice, ssa_cycle_f, 
     type="l", col = "magenta")


plot(dates_slice, ssa_sesonal_f, 
     type="l", col = "magenta")


plot(dates_slice, ssa_residuals_f,
     type="l", col = "magenta")

SSA eossa

library(Rssa)
source("eossa_new.r")
s <- ssa(IP_values_slice, L = 192)
e <- eossa_new(s, nested.groups = list(1:30), clust_type = "distance")




groups <- grouping.auto(e,
                   freq.bins = list(trend = c(1/192),
                                    cycle = c(1/97, 5/95),
                                    s1 = c(16/192 - eps, 16/192 + eps),
                                    s2 = c(32/192 - eps, 32/192 + eps),
                                    s3 = c(48/192 - eps, 48/192 + eps),
                                    s4 = c(64/192 - eps, 64/192 + eps),
                                    s5 = c(80/192 - eps, 80/192 + eps),
                                    s6 = c(96/192 - eps, 96/192 + eps)
                                    ),
                   threshold = 0)
plot(wcor(e, groups = 1:30), scales = list(at = c(10, 20, 30)),
     main = "W-correlation matrix SSA (eossa)")
Предупреждение в wcor.ossa(e, groups = 1:30) :
  Component matrices are not F-orthogonal (max F-cor is -0.0621). W-cor matrix can be irrelevant

r <- reconstruct(e, groups=groups)

ssa_trend <- r$trend
ssa_cycle <- r$cycle
ssa_sesonal <- r$s1 + r$s2 + r$s3 + r$s4 + r$s5 + r$s6
ssa_residuals <- IP_values_slice - (ssa_trend + ssa_cycle + ssa_sesonal)

plot(dates_slice, IP_values_slice,
     type="l", col = "black")
lines(dates_slice, ssa_trend,
      type="l", col = "blue")


plot(dates_slice, ssa_cycle, 
     type="l", col = "blue")


plot(dates_slice, ssa_sesonal, 
     type="l", col = "blue")


plot(dates_slice, ssa_residuals,
     type="l", col = "blue")

plot(dates_slice, IP_values_slice,
     main = "IP USA тренд",xlab = "Время", ylab = "Значение",
     type="l", col = "black")
lines(dates_slice, ssa_trend,
      type="l", col = "blue", lwd=2)
lines(dates_slice, ssa_trend_f,
      type="l", col = "magenta", lwd=2)
lines(dates_slice, cissa_trend,
      type="l", col = "red", lwd=2)
# Легенда
legend("topleft", legend = c("Весь ряд", "CiSSA тренд", "SSA тренд (eossa)", "SSA тренд (fossa)"), 
       col = c("black", "red", "blue", "magenta"), lty = 1, lwd = 3)



plot(dates_slice, ssa_cycle,
     main = "IP USA цикличность", xlab = "Время", ylab = "Значение",
     type="l", col = "blue", ylim=c(-10, 10), lwd=2)
lines(dates_slice, cissa_cycle,
      type="l", col = "red", lwd=2)
lines(dates_slice, ssa_cycle_f,
      type="l", col = "magenta", lwd=2)
# Легенда
legend("topleft", legend = c("CiSSA", "SSA (eossa)", "SSA (fossa)"), 
       col = c("red", "blue", "magenta"), lty = 1, lwd = 3)

# Настройка графиков для отображения двух графиков один под другим с общей осью X
layout(matrix(c(1, 2), nrow = 2, byrow = TRUE), heights = c(1, 1.2))

# Построение первого графика
par(mar = c(2, 4, 2, 2)) # Уменьшение нижнего отступа
plot(dates_slice, ssa_sesonal, type = "l", col = "blue", lwd = 1,
     main = "SSA (eossa) сезонность", xlab = "", ylab = "Значение")
# Добавление оси X внизу первого графика, но с пустыми метками
axis(1, labels = FALSE)

# Построение второго графика
par(mar = c(5, 4, 2, 2)) # Увеличение нижнего отступа
plot(dates_slice, ssa_sesonal_f, type = "l", col = "magenta", lwd = 1,
     main = "SSA (fossa) сезонность", xlab = "Время", ylab = "Значение")

par(mar = c(3, 4, 2, 2)) # Увеличение нижнего отступа

plot(dates_slice, cissa_sesonal, type = "l", col = "red", lwd = 1,
     main = "CiSSA сезонность", xlab = "Время", ylab = "Значение")

# Восстановление макета по умолчанию
layout(1)

NA
NA
plot(dates_slice, ssa_residuals, 
     main = "IP USA остаток", xlab = "Время", ylab = "Значение",
     type="l", col = "blue", ylim=c(-2, 2))
lines(dates_slice, cissa_residuals,
      type="l", col = "red")
lines(dates_slice, ssa_residuals_f,
      type="l", col = "magenta")
legend("topleft", legend = c("CiSSA", "SSA (eossa)", "SSA (fossa)"), 
       col = c("red", "blue", "magenta"), lty = 1, lwd = 3)

ssa_residuals |> density() |> plot()

cissa_residuals |> density() |> plot()

Отделение сигнала от шума

set.seed(100)

n_mse_tests <- function(n){
  n <- 96*2-1
  L <- 96
  sigma <- 0.1
  
  
  C <- 1
  omega_cs <- 1/12
  omega_sn <- 1/24
  a <- 1/100
  f_sum <- function(x){
    f_const(x, C = C) +
      f_cos(x, omega = omega_cs) +
      f_exp(x, a = a) +
      f_sin(x, omega = omega_sn)
  }
  
  
  f_C <- f_const |> generate_ts(n, C = C)
  f_c <- f_cos |> generate_ts(n, omega = omega_cs)
  f_s <- f_sin |> generate_ts(n, omega = omega_sn)
  f_e <- f_exp |> generate_ts(n, a = a)
  
  mse_lst <- list()
  for (i in 1:n) {
    f_noise <- rnorm(n, sd = sigma)
    
    f_n <- f_sum(1:n) + f_noise
    
    
    
    c <- circulant_SSA(f_n, L = L, extend_flag = TRUE)
    # r <- c$t_series
    r <- grouping_cissa(c, groups= list(trend = c(0, 1/1000), 
                                        sesonal2 = c(1/25, 1/23),
                                        sesonal1 = c(1/13, 1/10)
                                        ))$t_series
    
    # mse_lst$cissa <- c(mse_lst$cissa, mse(f_sum(1:n), r[, 9] + r[, 5] + r[, 1])) 
    mse_lst$cissa <- c(mse_lst$cissa,
                       mse(f_sum(1:n),
                           r$trend + r$sesonal1 + r$sesonal2)) 
    
    
    
    
    s <- ssa(f_n, L)
    # e <- eossa(s, 1:10, k = 6)
    e <- fossa(s)
    
    g_sesonal <- grouping.auto(e, base = "eigen",
                       freq.bins = list(trend = 1/1000, 
                                        sesonal2 = c(1/25, 1/23),
                                        sesonal1 = c(1/13, 1/10)
                                        ),
                       threshold = 0.5)
    
    r <- reconstruct(e, groups=c(list(exp = 1, C = 2), g_sesonal))
    
    mse_lst$ssa <- 
      c(mse_lst$ssa, mse(f_sum(1:n), r$trend + r$sesonal2 + r$sesonal1))
 
  }
  return(mse_lst)
}

res_mse_test <- n_mse_tests(10000)
# Оценка плотности
density_estimate_cissa <- density(res_mse_test$cissa)

# Построение графика плотности
plot(density_estimate_cissa, main = "Оценка плотности", 
     xlab = "Значение", ylab = "Плотность", 
     col = "blue", lwd = 2)


density_estimate_ssa <- density(res_mse_test$ssa)

# Построение графика плотности
plot(density_estimate_ssa, main = "Оценка плотности", 
     xlab = "Значение", ylab = "Плотность", 
     col = "blue", lwd = 2)


res_mse_test$cissa |> summary()
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
0.02299 0.03062 0.03345 0.03378 0.03575 0.04800 
res_mse_test$cissa |> sd()
[1] 0.004333975
res_mse_test$ssa |> summary()
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
0.000576 0.001710 0.002125 0.002228 0.002585 0.006311 
res_mse_test$ssa |> sd()
[1] 0.0008283841

Как выполняется расширение ряда

IP_values_slice |> extend(268) |> length()
[1] 1073
IP_values_slice |> length()
[1] 537
IP_values_slice |> extend(192) |> plot(type="l", lwd = 3)
c(rep(0, 192),IP_values_slice) |> lines(type="l", col="red")

|

n <- 96*2 + 6
x <- 0:(n-1)
y <- sin(2*pi/12 * x)
L <- 96+6
y |> extend(L) |> plot(type="l", lwd = 3)
c(rep(0, L), y) |> lines(type="l", col="red", lwd = 3)

CiSSA через Фурье

IP_values

cissa_like_fourier_transform <- function(ts, L){
  reconstruct_fft <- function(x, y, frequencies) {
    fft_y <- fft(y)
  
    amplitudes <- Mod(fft_y)
    phases <- Arg(fft_y)
    
    reconstructed <- matrix(0, length(amplitudes), length(x))
    n <- length(amplitudes)
    for (i in 1:(length(amplitudes))) {
      reconstructed[i, ] <-
        amplitudes[i] * 
        cos(2 * pi * frequencies[i] * (x) + phases[i]) /
        n
    }
    return(list(
      ts = reconstructed,
      frequencies = frequencies
      ))
  }
  
  n <- length(ts)
  x <- 0:(n-1)
  L <- L
  frequencies <- (0:(L-1)) / L
  y <- ts
  y_main <- y
  x_main <- x
  
  X <- hankel(y, L)
  K <- dim(X)[2]
  res <- list()
  for (i in 1:K){
    y <- X[, i]
    x <- x_main[1:(1 + L - 1)]
    res[[i]] <- reconstruct_fft(x, y, frequencies)$ts
  }
  
  # for (i in 1:L){
  #   plot(x, res[[i]][9, ])
  # }
  
  res_mult <- res
  # res
  
  averaging <- function(res_comp_wise_mult){
    K <- dim(X)[2]
    counters <- rep(0, n)
    res <- matrix(0, ncol = n, nrow = L)
    for (i in 1:length(res_comp_wise_mult)){
      res[, i:(i+L-1)] <- res[, i:(i+L-1)] + res_comp_wise_mult[[i]]
      counters[i:(i+L-1)] <- counters[i:(i+L-1)] + 1
    }
    for (i in 1:n){
      res[, i] <- res[, i] / counters[i]
    }
    res
  }
  
  avr <- averaging(res_mult)
  
  group_by_elementary_freq_foureir <- function(res_averaged){
    nf2 <- 0
    if (L %% 2) {
      nf2 <- (L + 1) / 2 - 1
    } else {
      nf2 <- L / 2 - 1
    }
    nft <- nf2 + abs((L %% 2) - 2)
    
    Z <- matrix(0, ncol = nft, nrow = n)
    
    # print(Z |> dim())
    # print(res_averaged |> dim())
    
    Z[, 1] <- res_averaged[1, ]
    for (k in 1:nf2) {
      Z[, k + 1] <- res_averaged[k + 1, ] + res_averaged[L + 2 - (k + 1), ]
    }
    if (L %% 2 != 0) {
      Z[, nft] <- res_averaged[nft, ]
    }
    
    
    return(list(
      t_series = Z,
      freq = (0:dim(Z)[2])/L
    ))
  }


  rs <- group_by_elementary_freq_foureir(avr)
  return(rs)
}
data_slice <- 1:537
dates_slice <- dates[data_slice]
IP_values_slice <- IP_values[data_slice]
eps <- 1/193


c <- circulant_SSA(IP_values_slice, L = 192, extend_flag = FALSE)
r <- c$t_series

c_ft <- cissa_like_fourier_transform(IP_values_slice, L = 192)
r_ft <- c_ft$t_series

for (i in 1:dim(r)[2]){
  plot(data_slice, r_ft[, i], col= "red", type = "l", lwd = 2)
  lines(data_slice, r[, i])
}

Сравнение разложений всего временного ряда через метод Фурье, SSA, auto_SSA, CiSSA и CiSSA с расширением ряда

reconstruct_fft <- function(x_init, y_init, extend_flag = FALSE) {
    x <- x_init
    y <- y_init
    N <- length(y_init)
    H <- 0
    if (extend_flag == TRUE){
      H <- length(y) %/% 2
      y <- extend(y, H)
      x <- 0:(length(y) - 1)
    }
    
    frequencies <- (0:(length(x)-1)) / length(x)
    fft_y <- fft(y)
    
    amplitudes <- Mod(fft_y)
    phases <- Arg(fft_y)
    
    reconstructed <- matrix(0, length(amplitudes), length(x))
    n <- length(amplitudes)
    L <- n
    for (i in 1:(length(amplitudes))) {
      reconstructed[i, ] <-
        amplitudes[i] * 
        cos(2 * pi * frequencies[i] * (x) + phases[i]) /
        n
    }
    
    
    
  
    group_by_elementary_freq_foureir <- function(res_averaged){
      nf2 <- 0
      if (L %% 2) {
        nf2 <- (L + 1) / 2 - 1
      } else {
        nf2 <- L / 2 - 1
      }
      nft <- nf2 + abs((L %% 2) - 2)
      
      Z <- matrix(0, ncol = nft, nrow = n)
      
      # print(Z |> dim())
      # print(res_averaged |> dim())
      
      Z[, 1] <- res_averaged[1, ]
      for (k in 1:nf2) {
        Z[, k + 1] <- res_averaged[k + 1, ] + res_averaged[L + 2 - (k + 1), ]
      }
      if (L %% 2 != 0) {
        Z[, nft] <- res_averaged[nft, ]
      }
      
      
      return(list(
        t_series = Z[(H+1):(N+H), ],
        freq = (0:(dim(Z)[2]-1))/L
      ))
    }
  
  
    rs <- group_by_elementary_freq_foureir(reconstructed)
    
    
    return(list(
      t_series = rs$t_series,
      freq = rs$freq
      ))
  }

Идеальный случай для CiSSA и Fourier

n <- 96*2
L <- 96
x <- 0:(n-1)
y1 <- sin(2*pi/12 * x)
y2 <- cos(2*pi/3 * x)/2
y <- y1 + y2
X <- hankel(y, L = L)
eps <- 1/(n+1)

s_ssa <- ssa(y[1:(n-1)], L)
r_ssa <- reconstruct(s_ssa, groups = list(
  F1 = c(1, 2),
  F2 = c(3, 4)
))
# r_ssa <- reconstruct(s_ssa, groups=list(
#   sesonal_sin = c(1, 2),
#   sesonal_cos = c(3, 4)
# ))
# plot(x, r_ssa$F1, type="l")
# plot(x, r_ssa$F2, type= "l")
# plot(wcor(s_ssa, groups = 1:10), scales = list(at = c(10, 20, 30)))
e_ssa <- eossa_new(s_ssa, nested.groups = list(1:4), clust_type = "distance")
g_sesonal_e <- grouping.auto(e_ssa, base = "eigen",
                       freq.bins = list(
                         sesonal_sin = c(1/12-eps, 1/12+eps),
                         sesonal_cos = c(1/3-eps, 1/3+eps)
                                        ),
                       threshold = 0.5)
r_ssa_e <- reconstruct(e_ssa, groups=g_sesonal_e)
# plot(x, r_ssa_e$sesonal_sin)
# plot(x, r_ssa_e$sesonal_cos)



r_fft <- reconstruct_fft(x, y)
r_fft_grouped <- grouping_cissa(r_fft,
                    groups = list(
                      sesonal_sin = c(1/12-eps, 1/12+eps),
                      sesonal_cos = c(1/3-eps, 1/3+eps)
                    )
                    )$t_series

r_fft_extended <- reconstruct_fft(x, y, TRUE)
r_fft_grouped_extended <- grouping_cissa(r_fft_extended,
                    groups = list(
                      sesonal_sin = c(1/12-eps, 1/12+eps),
                      sesonal_cos = c(1/3-eps, 1/3+eps)
                    )
                    )$t_series

# r_fft_grouped$sesonal_sin |> length()

# plot(x, r_fft_grouped$sesonal_sin)
# plot(x, r_fft_grouped$sesonal_cos)
# plot(x, r_fft_grouped$residuals)


r_cissa <- circulant_SSA(y, L)
r_cissa_grouped <- grouping_cissa(r_cissa,
                    groups = list(
                      sesonal_sin = c(1/12-eps, 1/12+eps),
                      sesonal_cos = c(1/3-eps, 1/3+eps)
                    )
                    )$t_series


r_cissa_ext <- circulant_SSA(y, L, extend_flag = TRUE)
r_cissa_grouped_ext <- grouping_cissa(r_cissa_ext,
                    groups = list(
                      sesonal_sin = c(1/12-eps, 1/12+eps),
                      sesonal_cos = c(1/3-eps, 1/3+eps)
                    )
                    )$t_series

# plot(x, r_cissa_grouped$sesonal_sin)
# plot(x, r_cissa_grouped$sesonal_cos)
# plot(x, r_cissa_grouped$residuals)

library(xtable)

# Шаг 2: Создание примера данных
data <- data.frame(
  Метод = c("SSA", "SSA EOSSA","Fourier", "CiSSA", "CiSSA extended", "Fourier extended"),
  sin_err = c (1, 20, 20, 1, 1, 1),
  cos_err = c(1, 1, 1, 1, 1, 1)
)

data$sin_err[1] <- mse(y1[1:(n-1)], r_ssa$F1) |>
  formatC(format = "e", digits = 1) 
data$cos_err[1] <- mse(y2[1:(n-1)], r_ssa$F2) |>
  formatC(format = "e", digits = 1)

data$cos_err[2] <- mse(y1[1:(n-1)], r_ssa_e$sesonal_sin) |>
  formatC(format = "e", digits = 1)
data$sin_err[2] <- mse(y2[1:(n-1)], r_ssa_e$sesonal_cos) |>
  formatC(format = "e", digits = 1)


data$cos_err[3] <- mse(y1, r_fft_grouped$sesonal_sin) |>
  formatC(format = "e", digits = 1)
data$sin_err[3] <- mse(y2, r_fft_grouped$sesonal_cos) |>
  formatC(format = "e", digits = 1)


data$cos_err[4] <- mse(y1, r_cissa_grouped$sesonal_sin) |> 
  formatC(format = "e", digits = 1)
data$sin_err[4] <- mse(y2, r_cissa_grouped$sesonal_cos) |> 
  formatC(format = "e", digits = 1)


data$cos_err[5] <- mse(y1, r_cissa_grouped_ext$sesonal_sin) |> 
  formatC(format = "e", digits = 1)
data$sin_err[5] <- mse(y2, r_cissa_grouped_ext$sesonal_cos) |> 
  formatC(format = "e", digits = 1)

data$cos_err[6] <- mse(y1, r_fft_grouped_extended$sesonal_sin) |>
  formatC(format = "e", digits = 1)
data$sin_err[6] <- mse(y2, r_fft_grouped_extended$sesonal_cos) |>
  formatC(format = "e", digits = 1)



table_latex <- xtable(data, caption = "Example Table")

# Шаг 4: Вывод таблицы в LaTeX файл
print(table_latex, include.rownames = FALSE)
% latex table generated in R 4.2.2 by xtable 1.8-4 package
% Thu Nov 28 19:49:16 2024
\begin{table}[ht]
\centering
\begin{tabular}{lll}
  \hline
Метод & sin\_err & cos\_err \\ 
  \hline
SSA & 6.8e-30 & 1.5e-29 \\ 
  SSA EOSSA & 1.5e-29 & 7.5e-30 \\ 
  Fourier & 1.7e-28 & 3.5e-28 \\ 
  CiSSA & 1.9e-29 & 5.3e-30 \\ 
  CiSSA extended & 2.0e-04 & 8.6e-04 \\ 
  Fourier extended & 6.2e-04 & 2.6e-03 \\ 
   \hline
\end{tabular}
\caption{Example Table} 
\end{table}

Идеальный случай с шумом


data <- list(
  Метод = c("SSA","SSA EOSSA","Fourier", "CiSSA", "CiSSA extended", "Fourier extended"),
  sin_err = list(list(), list(), list(), list(), list(), list()),
  cos_err = list(list(), list(), list(), list(), list(), list())
)

for (i in 1:50){
  set.seed(i)
  
  n <- 96*2
  L <- 96
  x <- 0:(n-1)
  y1 <- sin(2*pi/12 * x)
  y2 <- cos(2*pi/3 * x)/2
  y <- y1 + y2 + rnorm(n, 0, 0.1)
  X <- hankel(y, L = L)
  eps <- 1/(n+1)
  
  s_ssa <- ssa(y[1:(n-1)], L)
  r_ssa <- reconstruct(s_ssa, groups = list(
    F1 = c(1, 2),
    F2 = c(3, 4)
  ))
  # r_ssa <- reconstruct(s_ssa, groups=list(
  #   sesonal_sin = c(1, 2),
  #   sesonal_cos = c(3, 4)
  # ))
  # plot(x[1:(n-1)], r_ssa$F1, type = "l")
  # plot(x[1:(n-1)], r_ssa$F2, type = "l")
  # plot(wcor(s_ssa, groups = 1:10), scales = list(at = c(10, 20, 30)))
  e_ssa <- eossa_new(s_ssa, nested.groups = list(1:4), clust_type = "distance")
  g_sesonal_e <- grouping.auto(e_ssa, base = "eigen",
                         freq.bins = list(
                           sesonal_sin = c(1/12-eps, 1/12+eps),
                           sesonal_cos = c(1/3-eps, 1/3+eps)
                                          ),
                         threshold = 0.5)
  r_ssa_e <- reconstruct(e_ssa, groups=g_sesonal_e)
  # plot(x, r_ssa_e$sesonal_sin)
  # plot(x, r_ssa_e$sesonal_cos)
  
  
  
  r_fft <- reconstruct_fft(x, y)
  r_fft_grouped <- grouping_cissa(r_fft,
                      groups = list(
                        sesonal_sin = c(1/12-eps, 1/12+eps),
                        sesonal_cos = c(1/3-eps, 1/3+eps)
                      )
                      )$t_series
  
  r_fft_extended <- reconstruct_fft(x, y, TRUE)
  r_fft_grouped_extended <- grouping_cissa(r_fft_extended,
                      groups = list(
                        sesonal_sin = c(1/12-eps, 1/12+eps),
                        sesonal_cos = c(1/3-eps, 1/3+eps)
                      )
                      )$t_series
  
  # r_fft_grouped$sesonal_sin |> length()
  
  # plot(x, r_fft_grouped$sesonal_sin)
  # plot(x, r_fft_grouped$sesonal_cos)
  # plot(x, r_fft_grouped$residuals)
  
  
  r_cissa <- circulant_SSA(y, L)
  r_cissa_grouped <- grouping_cissa(r_cissa,
                      groups = list(
                        sesonal_sin = c(1/12-eps, 1/12+eps),
                        sesonal_cos = c(1/3-eps, 1/3+eps)
                      )
                      )$t_series
  
  
  r_cissa_ext <- circulant_SSA(y, L, extend_flag = TRUE)
  r_cissa_grouped_ext <- grouping_cissa(r_cissa_ext,
                      groups = list(
                        sesonal_sin = c(1/12-eps, 1/12+eps),
                        sesonal_cos = c(1/3-eps, 1/3+eps)
                      )
                      )$t_series
  data$cos_err[[1]][[i]] <- 
    min(mse(y1[1:(n-1)], r_ssa$F1), mse(y1[1:(n-1)], r_ssa$F2))
  data$sin_err[[1]][[i]] <-
    min(mse(y2[1:(n-1)], r_ssa$F1), mse(y2[1:(n-1)], r_ssa$F2))
  
  data$cos_err[[2]][[i]] <- mse(y1[1:(n-1)], r_ssa_e$sesonal_sin)
  data$sin_err[[2]][[i]] <- mse(y2[1:(n-1)], r_ssa_e$sesonal_cos)
  
  
  data$cos_err[[3]][[i]] <- mse(y1, r_fft_grouped$sesonal_sin)
  data$sin_err[[3]][[i]] <- mse(y2, r_fft_grouped$sesonal_cos)
  
  
  data$cos_err[[4]][[i]] <- mse(y1, r_cissa_grouped$sesonal_sin)
  data$sin_err[[4]][[i]] <- mse(y2, r_cissa_grouped$sesonal_cos)
  
  
  data$cos_err[[5]][[i]] <- mse(y1, r_cissa_grouped_ext$sesonal_sin)
  data$sin_err[[5]][[i]] <- mse(y2, r_cissa_grouped_ext$sesonal_cos)
  
  data$cos_err[[6]][[i]] <- mse(y1, r_fft_grouped_extended$sesonal_sin)
  data$sin_err[[6]][[i]] <- mse(y2, r_fft_grouped_extended$sesonal_cos)
}
library(xtable)

# Шаг 2: Создание примера данных
data_prev <- data

data <- data.frame(
  Метод = c("SSA", "SSA EOSSA","Fourier", "CiSSA", "CiSSA extended", "Fourier extended"),
  sin_err = c(0, 0, 0, 0, 0, 0),
  cos_err = c(0, 0, 0, 0, 0, 0)
)

data$cos_err[1] <- mean(data_prev$cos_err[[1]] |> unlist()) |>
  formatC(format = "e", digits = 1)
data$sin_err[1] <- mean(data_prev$sin_err[[1]]|> unlist()) |>
  formatC(format = "e", digits = 1)

data$cos_err[2] <- mean(data_prev$cos_err[[2]] |> unlist()) |>
  formatC(format = "e", digits = 1)
data$sin_err[2] <- mean(data_prev$sin_err[[2]]|> unlist()) |>
  formatC(format = "e", digits = 1)


data$cos_err[3] <- mean(data_prev$cos_err[[3]]|> unlist()) |>
  formatC(format = "e", digits = 1)
data$sin_err[3] <- mean(data_prev$sin_err[[3]]|> unlist()) |>
  formatC(format = "e", digits = 1)


data$cos_err[4] <- mean(data_prev$cos_err[[4]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
data$sin_err[4] <- mean(data_prev$sin_err[[4]]|> unlist()) |> 
  formatC(format = "e", digits = 1)


data$cos_err[5] <- mean(data_prev$cos_err[[5]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
data$sin_err[5] <- mean(data_prev$sin_err[[5]]|> unlist()) |> 
  formatC(format = "e", digits = 1)

data$cos_err[6] <- mean(data_prev$cos_err[[6]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
data$sin_err[6] <- mean(data_prev$sin_err[[6]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
for (i in 1:4){
  for (j in (i):4){
    x <- data_prev$cos_err[[i]] |> unlist()
    y <- data_prev$cos_err[[j]] |> unlist()
    t_test_result <- t.test(x, y, paired = TRUE)
    print(paste("cos, ", data$Метод[i], " ", data$Метод[j], ", p-val = ", t_test_result$p.value))
  }
}
[1] "cos,  SSA   SSA , p-val =  NaN"
[1] "cos,  SSA   SSA EOSSA , p-val =  0.038881875174499"
[1] "cos,  SSA   Fourier , p-val =  3.63996112806195e-10"
[1] "cos,  SSA   CiSSA , p-val =  1.69300523929475e-11"
[1] "cos,  SSA EOSSA   SSA EOSSA , p-val =  NaN"
[1] "cos,  SSA EOSSA   Fourier , p-val =  3.61837650659192e-10"
[1] "cos,  SSA EOSSA   CiSSA , p-val =  1.68793475607746e-11"
[1] "cos,  Fourier   Fourier , p-val =  NaN"
[1] "cos,  Fourier   CiSSA , p-val =  1.84590409706372e-05"
[1] "cos,  CiSSA   CiSSA , p-val =  NaN"
for (i in 1:4){
  for (j in (i):4){
    x <- data_prev$sin_err[[i]] |> unlist()
    y <- data_prev$sin_err[[j]] |> unlist()
    t_test_result <- t.test(x, y, paired = TRUE)
    print(paste("sin, ", data$Метод[i], " ", data$Метод[j], ", p-val = ", t_test_result$p.value))
  }
}
[1] "sin,  SSA   SSA , p-val =  NaN"
[1] "sin,  SSA   SSA EOSSA , p-val =  3.71816430587151e-11"
[1] "sin,  SSA   Fourier , p-val =  5.97385946308374e-13"
[1] "sin,  SSA   CiSSA , p-val =  2.11234626356184e-13"
[1] "sin,  SSA EOSSA   SSA EOSSA , p-val =  NaN"
[1] "sin,  SSA EOSSA   Fourier , p-val =  5.89508148968624e-13"
[1] "sin,  SSA EOSSA   CiSSA , p-val =  2.13061715482733e-13"
[1] "sin,  Fourier   Fourier , p-val =  NaN"
[1] "sin,  Fourier   CiSSA , p-val =  2.79473942754082e-06"
[1] "sin,  CiSSA   CiSSA , p-val =  NaN"
table_latex <- xtable(data, caption = "Example Table")

# Шаг 4: Вывод таблицы в LaTeX файл
print(table_latex, include.rownames = FALSE)
% latex table generated in R 4.2.2 by xtable 1.8-4 package
% Thu Nov 28 19:53:46 2024
\begin{table}[ht]
\centering
\begin{tabular}{lll}
  \hline
Метод & sin\_err & cos\_err \\ 
  \hline
SSA & 3.2e-04 & 3.0e-04 \\ 
  SSA EOSSA & 3.2e-04 & 3.0e-04 \\ 
  Fourier & 1.3e-04 & 1.1e-04 \\ 
  CiSSA & 1.8e-04 & 1.8e-04 \\ 
  CiSSA extended & 7.1e-04 & 1.9e-03 \\ 
  Fourier extended & 1.3e-03 & 3.9e-03 \\ 
   \hline
\end{tabular}
\caption{Example Table} 
\end{table}

Добавим непериодичность

n <- 96*2
x <- 0:(n-1)
L <- 96
y1 <- sin(2*pi/12 * x)
y2 <- cos(2*pi/3 * x)/2
y3 <- exp(x/100) + 1
y <- y1 + y2 + y3
eps <- 1/(n+1)

s_ssa <- ssa(y[1:(n-1)], L)
r_ssa <- reconstruct(s_ssa, groups=list(
  e = c(1),
  sesonal_sin = c(2, 3),
  sesonal_cos = c(4, 5)
))
# plot(x[1:(n-1)], r_ssa$e, type = "l")
# plot(x[1:(n-1)], r_ssa$sesonal_sin, type = "l")
# plot(x[1:(n-1)], r_ssa$sesonal_cos, type = "l")
# plot(wcor(s_ssa, groups = 1:10), scales = list(at = c(10, 20, 30)))
e_ssa <- eossa_new(s_ssa, nested.groups = list(1:7), clust_type = "distance")
g_sesonal_e <- grouping.auto(e_ssa, base = "eigen",
                       freq.bins = list(
                         e = c(0, 1/12-eps-eps),
                         sesonal_sin = c(1/12-eps, 1/12+eps),
                         sesonal_cos = c(1/3-eps, 1/3+eps)
                                        ),
                       threshold = 0.5)
r_ssa_e <- reconstruct(e_ssa, groups=g_sesonal_e)
# plot(x, r_ssa_e$sesonal_sin)
# plot(x, r_ssa_e$sesonal_cos)



r_fft <- reconstruct_fft(x, y)
r_fft_grouped <- grouping_cissa(r_fft,
                    groups = list(
                      e = c(0, 1/12-eps-eps),
                      sesonal_sin = c(1/12-eps, 1/12+eps),
                      sesonal_cos = c(1/3-eps, 1/3+eps)
                    )
                    )$t_series

r_fft_extended <- reconstruct_fft(x, y, TRUE)
r_fft_grouped_extended <- grouping_cissa(r_fft_extended,
                    groups = list(
                      e = c(0, 1/12-eps-eps),
                      sesonal_sin = c(1/12-eps, 1/12+eps),
                      sesonal_cos = c(1/3-eps, 1/3+eps)
                    )
                    )$t_series

# r_fft_grouped$sesonal_sin |> length()

# plot(x, r_fft_grouped$sesonal_sin)
# plot(x, r_fft_grouped$sesonal_cos)
# plot(x, r_fft_grouped$residuals)


r_cissa <- circulant_SSA(y, L)
r_cissa_grouped <- grouping_cissa(r_cissa,
                    groups = list(
                      e = c(0, 1/12-eps-eps),
                      sesonal_sin = c(1/12-eps, 1/12+eps),
                      sesonal_cos = c(1/3-eps, 1/3+eps)
                    )
                    )$t_series


r_cissa_ext <- circulant_SSA(y, L, extend_flag = TRUE)
r_cissa_grouped_ext <- grouping_cissa(r_cissa_ext,
                    groups = list(
                      e = c(0, 1/12-eps-eps),
                      sesonal_sin = c(1/12-eps, 1/12+eps),
                      sesonal_cos = c(1/3-eps, 1/3+eps)
                    )
                    )$t_series

# plot(x, r_cissa_grouped$sesonal_sin)
# plot(x, r_cissa_grouped$sesonal_cos)
# plot(x, r_cissa_grouped$residuals)

library(xtable)

# Шаг 2: Создание примера данных
data <- data.frame(
  Метод = c("SSA", "SSA EOSSA","Fourier", "CiSSA", "CiSSA extended", "Fourier extended"),
  e_err = c(1, 1, 1, 1, 1, 1),
  sin_err = c (1, 20, 20, 1, 1, 1),
  cos_err = c(1, 1, 1, 1, 1, 1)
)

data$cos_err[1] <- mse(y1[1:(n-1)], r_ssa$sesonal_sin) |>
  formatC(format = "e", digits = 1)
data$sin_err[1] <- mse(y2[1:(n-1)], r_ssa$sesonal_cos) |>
  formatC(format = "e", digits = 1)
data$e_err[1] <- mse(y3[1:(n-1)], r_ssa$e) |>
  formatC(format = "e", digits = 1)

data$cos_err[2] <- mse(y1[1:(n-1)], r_ssa_e$sesonal_sin) |>
  formatC(format = "e", digits = 1)
data$sin_err[2] <- mse(y2[1:(n-1)], r_ssa_e$sesonal_cos) |>
  formatC(format = "e", digits = 1)
data$e_err[2] <- mse(y3[1:(n-1)], r_ssa_e$e) |>
  formatC(format = "e", digits = 1)


data$cos_err[3] <- mse(y1, r_fft_grouped$sesonal_sin) |>
  formatC(format = "e", digits = 1)
data$sin_err[3] <- mse(y2, r_fft_grouped$sesonal_cos) |>
  formatC(format = "e", digits = 1)
data$e_err[3] <- mse(y3, r_fft_grouped$e) |>
  formatC(format = "e", digits = 1)


data$cos_err[4] <- mse(y1, r_cissa_grouped$sesonal_sin) |> 
  formatC(format = "e", digits = 1)
data$sin_err[4] <- mse(y2, r_cissa_grouped$sesonal_cos) |> 
  formatC(format = "e", digits = 1)
data$e_err[4] <- mse(y3, r_cissa_grouped$e) |>
  formatC(format = "e", digits = 1)

data$cos_err[5] <- mse(y1, r_cissa_grouped_ext$sesonal_sin) |> 
  formatC(format = "e", digits = 1)
data$sin_err[5] <- mse(y2, r_cissa_grouped_ext$sesonal_cos) |> 
  formatC(format = "e", digits = 1)
data$e_err[5] <- mse(y3, r_cissa_grouped_ext$e) |>
  formatC(format = "e", digits = 1)

data$cos_err[6] <- mse(y1, r_fft_grouped_extended$sesonal_sin) |> 
  formatC(format = "e", digits = 1)
data$sin_err[6] <- mse(y2, r_fft_grouped_extended$sesonal_cos) |> 
  formatC(format = "e", digits = 1)
data$e_err[6] <- mse(y3, r_fft_grouped_extended$e) |>
  formatC(format = "e", digits = 1)



table_latex <- xtable(data, caption = "Example Table")

# Шаг 4: Вывод таблицы в LaTeX файл
print(table_latex, include.rownames = FALSE)
% latex table generated in R 4.2.2 by xtable 1.8-4 package
% Thu Nov 28 19:55:50 2024
\begin{table}[ht]
\centering
\begin{tabular}{llll}
  \hline
Метод & e\_err & sin\_err & cos\_err \\ 
  \hline
SSA & 5.0e-03 & 8.9e-07 & 5.2e-05 \\ 
  SSA EOSSA & 1.7e-28 & 1.6e-29 & 8.7e-30 \\ 
  Fourier & 1.1e-01 & 6.1e-04 & 6.8e-03 \\ 
  CiSSA & 5.3e-02 & 1.6e-05 & 4.9e-04 \\ 
  CiSSA extended & 5.0e-04 & 2.1e-04 & 1.1e-03 \\ 
  Fourier extended & 1.4e-03 & 1.3e-03 & 8.4e-03 \\ 
   \hline
\end{tabular}
\caption{Example Table} 
\end{table}

Непериодичность с шумом

# data <- data.frame(
#   Метод = c("Fourier", "CiSSA", "CiSSA с расширением ряда"),
#   sin_err = c (20, 20, 20),
#   cos_err = c(1, 1, 20),
#   exp_err = c(1, 1, 20)
# )
data <- list(
  Метод = c("SSA", "SSA EOSSA","Fourier", "CiSSA", "CiSSA extended", "Fourier extended"),
  sin_err = list(list(), list(), list(), list(), list(), list()),
  cos_err = list(list(), list(), list(), list(), list(), list()),
  exp_err = list(list(), list(), list(), list(), list(), list())
)

for (i in 1:100){
  set.seed(i)
  
  n <- 96*2
  x <- 0:(n-1)
  L <- 96
  y1 <- sin(2*pi/12 * x)
  y2 <- cos(2*pi/3 * x)/2
  y3 <- exp(x/100) + 1
  y <- y1 + y2 + y3 + rnorm(n, 0, 0.1)
  eps <- 1/(n+1)
  
  s_ssa <- ssa(y[1:(n-1)], L)
  r_ssa <- reconstruct(s_ssa, groups=list(
    e = 1,
    sesonal_sin = c(2, 3),
    sesonal_cos = c(4, 5)
  ))
  
  
  e_ssa <- eossa_new(s_ssa, nested.groups = list(1:6), clust_type = "distance")
  g_sesonal_e <- grouping.auto(e_ssa, base = "eigen",
                         freq.bins = list(
                           e = c(0, 1/12-eps-eps),
                           sesonal_sin = c(1/12-eps, 1/12+eps),
                           sesonal_cos = c(1/3-eps, 1/3+eps)
                                          ),
                         threshold = 0.5)
  r_ssa_e <- reconstruct(e_ssa, groups=g_sesonal_e)
  
  
  
  r_fft <- reconstruct_fft(x, y)
  r_fft_grouped <- grouping_cissa(r_fft,
                      groups = list(
                        e = c(0, 1/12-eps-eps),
                        sesonal_sin = c(1/12-eps, 1/12+eps),
                        sesonal_cos = c(1/3-eps, 1/3+eps)
                      )
                      )$t_series
  
  r_fft_extended <- reconstruct_fft(x, y, TRUE)
  r_fft_grouped_extended <- grouping_cissa(r_fft_extended,
                      groups = list(
                        e = c(0, 1/12-eps-eps),
                        sesonal_sin = c(1/12-eps, 1/12+eps),
                        sesonal_cos = c(1/3-eps, 1/3+eps)
                      )
                      )$t_series
  
  
  r_cissa <- circulant_SSA(y, L)
  r_cissa_grouped <- grouping_cissa(r_cissa,
                      groups = list(
                        e = c(0, 1/12-eps-eps),
                        sesonal_sin = c(1/12-eps, 1/12+eps),
                        sesonal_cos = c(1/3-eps, 1/3+eps)
                      )
                      )$t_series
  
  
  r_cissa_ext <- circulant_SSA(y, L, extend_flag = TRUE)
  r_cissa_grouped_ext <- grouping_cissa(r_cissa_ext,
                      groups = list(
                        e = c(0, 1/12-eps-eps),
                        sesonal_sin = c(1/12-eps, 1/12+eps),
                        sesonal_cos = c(1/3-eps, 1/3+eps)
                      )
                      )$t_series
  
  
  
  data$cos_err[[1]][[i]] <- mse(y1[1:(n-1)], r_ssa$sesonal_sin)
  data$sin_err[[1]][[i]] <- mse(y2[1:(n-1)], r_ssa$sesonal_cos)
  data$exp_err[[1]][[i]] <- mse(y3[1:(n-1)], r_ssa$e)
  
  data$cos_err[[2]][[i]] <- mse(y1[1:(n-1)], r_ssa_e$sesonal_sin)
  data$sin_err[[2]][[i]] <- mse(y2[1:(n-1)], r_ssa_e$sesonal_cos)
  data$exp_err[[2]][[i]] <- mse(y3[1:(n-1)], r_ssa_e$e)
  
  # print(data$sin_err[[2]][[i]])
  
  
  data$cos_err[[3]][[i]] <- mse(y1, r_fft_grouped$sesonal_sin)
  data$sin_err[[3]][[i]] <- mse(y2, r_fft_grouped$sesonal_cos)
  data$exp_err[[3]][[i]] <- mse(y3, r_fft_grouped$e)
  
  
  data$cos_err[[4]][[i]] <- mse(y1, r_cissa_grouped$sesonal_sin)
  data$sin_err[[4]][[i]] <- mse(y2, r_cissa_grouped$sesonal_cos)
  data$exp_err[[4]][[i]] <- mse(y3, r_cissa_grouped$e)
  
  
  data$cos_err[[5]][[i]] <- mse(y1, r_cissa_grouped_ext$sesonal_sin)
  data$sin_err[[5]][[i]] <- mse(y2, r_cissa_grouped_ext$sesonal_cos)
  data$exp_err[[5]][[i]] <- mse(y3, r_cissa_grouped_ext$e)
  
  data$cos_err[[6]][[i]] <- mse(y1, r_fft_grouped_extended$sesonal_sin)
  data$sin_err[[6]][[i]] <- mse(y2, r_fft_grouped_extended$sesonal_cos)
  data$exp_err[[6]][[i]] <- mse(y3, r_fft_grouped_extended$e)
}
library(xtable)
# data$sin_err[[2]]
# Шаг 2: Создание примера данных
data_prev <- data
data <- data.frame(
  Метод = c("SSA", "SSA EOSSA","Fourier", "CiSSA", "CiSSA extended", "Fourier extended"),
  sin_err = c(0, 0, 0, 0, 0, 0),
  cos_err = c(0, 0, 0, 0, 0, 0),
  exp_err = c(0, 0, 0, 0, 0, 0)
)

data$cos_err[1] <- mean(data_prev$cos_err[[1]] |> unlist()) |>
  formatC(format = "e", digits = 1)
data$sin_err[1] <- mean(data_prev$sin_err[[1]]|> unlist()) |>
  formatC(format = "e", digits = 1)
data$exp_err[1] <- mean(data_prev$exp_err[[1]]|> unlist()) |>
  formatC(format = "e", digits = 1)


data$cos_err[2] <- mean(data_prev$cos_err[[2]]|> unlist()) |>
  formatC(format = "e", digits = 1)
data$sin_err[2] <- mean(data_prev$sin_err[[2]]|> unlist()) |>
  formatC(format = "e", digits = 1)
data$exp_err[2] <- mean(data_prev$exp_err[[2]]|> unlist()) |>
  formatC(format = "e", digits = 1)


data$cos_err[3] <- mean(data_prev$cos_err[[3]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
data$sin_err[3] <- mean(data_prev$sin_err[[3]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
data$exp_err[3] <- mean(data_prev$exp_err[[3]]|> unlist()) |>
  formatC(format = "e", digits = 1)


data$cos_err[4] <- mean(data_prev$cos_err[[4]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
data$sin_err[4] <- mean(data_prev$sin_err[[4]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
data$exp_err[4] <- mean(data_prev$exp_err[[4]]|> unlist()) |>
  formatC(format = "e", digits = 1)

data$cos_err[5] <- mean(data_prev$cos_err[[5]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
data$sin_err[5] <- mean(data_prev$sin_err[[5]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
data$exp_err[5] <- mean(data_prev$exp_err[[5]]|> unlist()) |>
  formatC(format = "e", digits = 1)

data$cos_err[6] <- mean(data_prev$cos_err[[6]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
data$sin_err[6] <- mean(data_prev$sin_err[[6]]|> unlist()) |> 
  formatC(format = "e", digits = 1)
data$exp_err[6] <- mean(data_prev$exp_err[[6]]|> unlist()) |>
  formatC(format = "e", digits = 1)
for (i in 1:4){
  for (j in (i):4){
    x <- data_prev$cos_err[[i]] |> unlist()
    y <- data_prev$cos_err[[j]] |> unlist()
    t_test_result <- t.test(x, y, paired = TRUE)
    print(paste("cos, ", data$Метод[i], " ", data$Метод[j], ", p-val = ", t_test_result$p.value))
  }
}
[1] "cos,  SSA   SSA , p-val =  NaN"
[1] "cos,  SSA   SSA EOSSA , p-val =  1.15068669354673e-13"
[1] "cos,  SSA   Fourier , p-val =  1.15081927627114e-78"
[1] "cos,  SSA   CiSSA , p-val =  4.65220864068305e-44"
[1] "cos,  SSA EOSSA   SSA EOSSA , p-val =  NaN"
[1] "cos,  SSA EOSSA   Fourier , p-val =  6.8490552789737e-79"
[1] "cos,  SSA EOSSA   CiSSA , p-val =  7.58217507825911e-49"
[1] "cos,  Fourier   Fourier , p-val =  NaN"
[1] "cos,  Fourier   CiSSA , p-val =  4.1470816136733e-79"
[1] "cos,  CiSSA   CiSSA , p-val =  NaN"
for (i in 1:4){
  for (j in (i):4){
    x <- data_prev$sin_err[[i]] |> unlist()
    y <- data_prev$sin_err[[j]] |> unlist()
    t_test_result <- t.test(x, y, paired = TRUE)
    print(paste("sin, ", data$Метод[i], " ", data$Метод[j], ", p-val = ", t_test_result$p.value))
  }
}
[1] "sin,  SSA   SSA , p-val =  NaN"
[1] "sin,  SSA   SSA EOSSA , p-val =  0.273046993097837"
[1] "sin,  SSA   Fourier , p-val =  3.41671346310886e-19"
[1] "sin,  SSA   CiSSA , p-val =  2.68804866311398e-16"
[1] "sin,  SSA EOSSA   SSA EOSSA , p-val =  NaN"
[1] "sin,  SSA EOSSA   Fourier , p-val =  3.14261131207794e-19"
[1] "sin,  SSA EOSSA   CiSSA , p-val =  5.94062534986952e-16"
[1] "sin,  Fourier   Fourier , p-val =  NaN"
[1] "sin,  Fourier   CiSSA , p-val =  2.93671115450334e-28"
[1] "sin,  CiSSA   CiSSA , p-val =  NaN"
for (i in 1:4){
  for (j in (i):4){
    x <- data_prev$exp_err[[i]] |> unlist()
    y <- data_prev$exp_err[[j]] |> unlist()
    t_test_result <- t.test(x, y, paired = TRUE)
    print(paste("exp, ", data$Метод[i], " ", data$Метод[j], ", p-val = ", t_test_result$p.value))
  }
}
[1] "exp,  SSA   SSA , p-val =  NaN"
[1] "exp,  SSA   SSA EOSSA , p-val =  1.2968052853879e-78"
[1] "exp,  SSA   Fourier , p-val =  3.1975845882856e-218"
[1] "exp,  SSA   CiSSA , p-val =  6.62421968424602e-130"
[1] "exp,  SSA EOSSA   SSA EOSSA , p-val =  NaN"
[1] "exp,  SSA EOSSA   Fourier , p-val =  5.2539864487142e-262"
[1] "exp,  SSA EOSSA   CiSSA , p-val =  2.10736945563773e-133"
[1] "exp,  Fourier   Fourier , p-val =  NaN"
[1] "exp,  Fourier   CiSSA , p-val =  4.58655868843589e-140"
[1] "exp,  CiSSA   CiSSA , p-val =  NaN"
table_latex <- xtable(data, caption = "Example Table")

# Шаг 4: Вывод таблицы в LaTeX файл
print(table_latex, include.rownames = FALSE)
% latex table generated in R 4.2.2 by xtable 1.8-4 package
% Thu Nov 28 20:01:06 2024
\begin{table}[ht]
\centering
\begin{tabular}{llll}
  \hline
Метод & sin\_err & cos\_err & exp\_err \\ 
  \hline
SSA & 2.9e-04 & 3.6e-04 & 5.2e-03 \\ 
  SSA EOSSA & 2.9e-04 & 3.1e-04 & 9.4e-04 \\ 
  Fourier & 6.9e-04 & 7.2e-03 & 1.2e-01 \\ 
  CiSSA & 1.7e-04 & 7.0e-04 & 5.5e-02 \\ 
  CiSSA extended & 6.8e-04 & 2.1e-03 & 2.7e-03 \\ 
  Fourier extended & 1.9e-03 & 9.6e-03 & 3.0e-03 \\ 
   \hline
\end{tabular}
\caption{Example Table} 
\end{table}

Пример, который не подходит ни к какому методу

n <- 96*2 + 7
L <- 89
x <- 0:(n-1)
y1 <- sin(2*pi/13 * x)
y2 <- cos(2*pi/8 * x)
y3 <- -x*x/1000
y4 <- exp(x/55)
y <- y1 + y2 + y3 + y4 
plot(x, y)

X <- hankel(y, L = L)
eps <- 1/(n+1)

s_ssa <- ssa(y, L)
# r_ssa <- reconstruct(s_ssa, groups=list(
#   sesonal_sin = c(1, 2),
#   sesonal_cos = c(3, 4)
# ))
# plot(x, r_ssa$sesonal_sin)
# plot(x, r_ssa$sesonal_cos)
# plot(wcor(s_ssa, groups = 1:10), scales = list(at = c(10, 20, 30)))
e_ssa <- eossa_new(s_ssa, nested.groups = list(1:10), clust_type = "distance")
g_sesonal_e <- grouping.auto(e_ssa, base = "eigen",
                       freq.bins = list(
                         sesonal_sin = c(1/12-eps, 1/12+eps),
                         sesonal_cos = c(1/8-eps, 1/8+eps)
                                        ),
                       threshold = 0.5)
r_ssa_e <- reconstruct(e_ssa, groups=g_sesonal_e)
# plot(x, r_ssa_e$sesonal_sin)
# plot(x, r_ssa_e$sesonal_cos)



r_fft <- reconstruct_fft(x, y)
r_fft_grouped <- grouping_cissa(r_fft,
                    groups = list(
                      sesonal_sin = c(1/12-eps, 1/12+eps),
                      sesonal_cos = c(1/8-eps, 1/8+eps)
                    )
                    )$t_series

# r_fft_grouped$sesonal_sin |> length()

# plot(x, r_fft_grouped$sesonal_sin)
# plot(x, r_fft_grouped$sesonal_cos)
# plot(x, r_fft_grouped$residuals)


r_cissa <- circulant_SSA(y, L)
r_cissa_grouped <- grouping_cissa(r_cissa,
                    groups = list(
                      sesonal_sin = c(1/12-eps, 1/12+eps),
                      sesonal_cos = c(1/8-eps, 1/8+eps)
                    )
                    )$t_series


r_cissa_ext <- circulant_SSA(y, L, extend_flag = TRUE)
r_cissa_grouped_ext <- grouping_cissa(r_cissa_ext,
                    groups = list(
                      sesonal_sin = c(1/12-eps, 1/12+eps),
                      sesonal_cos = c(1/8-eps, 1/8+eps)
                    )
                    )$t_series

# plot(x, r_cissa_grouped$sesonal_sin)
# plot(x, r_cissa_grouped$sesonal_cos)
# plot(x, r_cissa_grouped$residuals)

library(xtable)

# Шаг 2: Создание примера данных
data <- data.frame(
  Метод = c("SSA EOSSA","Fourier", "CiSSA", "CiSSA extended"),
  sin_err = c (20, 20, 1, 1),
  cos_err = c(1, 1, 1, 1)
)

data$cos_err[1] <- mse(y1, r_ssa_e$sesonal_sin) |>
  formatC(format = "e", digits = 1)
data$sin_err[1] <- mse(y2, r_ssa_e$sesonal_cos) |>
  formatC(format = "e", digits = 1)


data$cos_err[2] <- mse(y1, r_fft_grouped$sesonal_sin) |>
  formatC(format = "e", digits = 1)
data$sin_err[2] <- mse(y2, r_fft_grouped$sesonal_cos) |>
  formatC(format = "e", digits = 1)


data$cos_err[3] <- mse(y1, r_cissa_grouped$sesonal_sin) |> 
  formatC(format = "e", digits = 1)
data$sin_err[3] <- mse(y2, r_cissa_grouped$sesonal_cos) |> 
  formatC(format = "e", digits = 1)


data$cos_err[4] <- mse(y1, r_cissa_grouped_ext$sesonal_sin) |> 
  formatC(format = "e", digits = 1)
data$sin_err[4] <- mse(y2, r_cissa_grouped_ext$sesonal_cos) |> 
  formatC(format = "e", digits = 1)



table_latex <- xtable(data, caption = "Example Table")

# Шаг 4: Вывод таблицы в LaTeX файл
print(table_latex, include.rownames = FALSE)
% latex table generated in R 4.2.2 by xtable 1.8-4 package
% Thu Nov 28 18:27:55 2024
\begin{table}[ht]
\centering
\begin{tabular}{lll}
  \hline
Метод & sin\_err & cos\_err \\ 
  \hline
SSA EOSSA & 2.1e-21 & 7.4e-22 \\ 
  Fourier & 1.6e-02 & 4.2e-01 \\ 
  CiSSA & 2.2e-02 & 3.7e-02 \\ 
  CiSSA extended & 2.9e-03 & 4.5e-03 \\ 
   \hline
\end{tabular}
\caption{Example Table} 
\end{table}
LS0tDQp0aXRsZTogIkNpcmN1bGFudCBTU0EiDQphdXRob3I6ICLQn9C+0LPRgNC10LHQvdC40LrQvtCyINCd0LjQutC+0LvQsNC5Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KYGBge3J9DQpMIDwtIDgxDQp4IDwtIDE6TA0KeSA8LSBzaW4ocGkqeC8oTCsxKSleMiB8PiBzcXJ0KCkgDQoNCnBsb3QoeCwgeSkNCmBgYA0KDQojIyDQktGB0L/QvtC80L7Qs9Cw0YLQtdC70YzQvdGL0LUg0YTRg9C90LrRhtC40LgNCg0KYGBge3J9DQpsaWJyYXJ5KFJzc2EpDQpsaWJyYXJ5KHNpZ25hbCkNCmxpYnJhcnkoZ3NpZ25hbCkNCnNvdXJjZSgiZW9zc2FfbmV3LlIiKQ0KDQoNCmRmdG10eCA8LSBmdW5jdGlvbihuKSB7DQogIHkgPC0gc3RhdHM6Om12ZmZ0KGRpYWcoMSwgbikpDQogIHkNCn0NCg0KZGlhZ19hdmVyYWdpbmcgPC0gZnVuY3Rpb24oQSl7DQogIEIgPC0gQVtucm93KEEpOjEsIF0gfD4gUmUoKQ0KICBsYXBwbHkoc3BsaXQoQiwgLShyb3coQikgLSBjb2woQikpICksIG1lYW4pIHw+IGFzLm51bWVyaWMoKQ0KfQ0KDQpzaGlmdF92ZWN0b3IgPC0gZnVuY3Rpb24odmVjKSB7DQogIGxhc3RfZWxlbWVudCA8LSB0YWlsKHZlYywgMSkNCiAgdmVjIDwtIHZlY1stbGVuZ3RoKHZlYyldDQogIHNoaWZ0ZWRfdmVjIDwtIGMobGFzdF9lbGVtZW50LCB2ZWMpDQogIHJldHVybihzaGlmdGVkX3ZlYykNCn0NCg0KZXh0ZW5kIDwtIGZ1bmN0aW9uKHgsIEgpew0KICAjINCS0YvRh9C40YHQu9C10L3QuNC1INC60L7RjdGE0YTQuNGG0LjQtdC90YLQvtCyIEFSINC80L7QtNC10LvQuCDQtNC70Y8g0LTQuNGE0YTQtdGA0LXQvdGG0LjRgNC+0LLQsNC90L3QvtCz0L4g0YDRj9C00LANCiAgTiA8LSBsZW5ndGgoeCkNCiAgcCA8LSBmbG9vcihOIC8gMykNCiAgZHggPC0gZGlmZih4KQ0KICAjIEEgPC0gYXIoZHgsIG9yZGVyLm1heCA9IHAsIG1ldGhvZCA9ICJ5dWxlLXdhbGtlciIpJGFyDQogIEEgPC0gYXJ5dWxlKGR4LCBwKSRhDQogIA0KICAjINCf0YDQsNCy0L7QtSDRgNCw0YHRiNC40YDQtdC90LjQtQ0KICB5IDwtIHgNCiAgZHkgPC0gZGlmZih5KQ0KICBlciA8LSBzaWduYWw6OmZpbHRlcihBLCAxLCBkeSkNCiAgZHkgPC0gc2lnbmFsOjpmaWx0ZXIoMSwgQSwgYyhlciwgcmVwKDAsIEgpKSkNCiAgeSA8LSB5WzFdICsgYygwLCBjdW1zdW0oZHkpKQ0KICANCiAgIyDQm9C10LLQvtC1INGA0LDRgdGI0LjRgNC10L3QuNC1DQogIHkgPC0gcmV2KHkpDQogIGR5IDwtIGRpZmYoeSkNCiAgZXIgPC0gc2lnbmFsOjpmaWx0ZXIoQSwxLGR5KQ0KICBkeSA8LSBzaWduYWw6OmZpbHRlcigxLEEsYyhlciwgcmVwKDAsIEgpKSkNCiAgeSA8LSB5WzFdICsgYygwLCBjdW1zdW0oZHkpKQ0KICANCiAgIyDQoNCw0YHRiNC40YDQtdC90L3Ri9C5INGA0Y/QtA0KICB4ZSA8LSByZXYoeSkNCiAgDQogICMg0JLRi9Cy0L7QtCDRgNC10LfRg9C70YzRgtCw0YLQvtCyDQogIHhlIA0KfQ0KYGBgDQoNCiMjIENpU1NBDQoNCtCf0L7QtNCw0ZHRgtGB0Y8g0L3QsCDQstGF0L7QtCDQstGA0LXQvNC10L3QvdC+0Lkg0YDRj9C0LCDQtNC70LjQvdCwINC+0LrQvdCwICjQtdGB0LvQuCDQtdGRINC90LXRgiwg0YLQviDQvtC90LAg0YDQsNCy0L3QsCDQtNC70LjQvdC1INGA0Y/QtNCwICsgMSDQv9C+0L/QvtC70LDQvCkg0Lgg0LjQvdGE0L7RgNC80LDRhtC40Y8g0L4g0YLQvtC8LCDQvdGD0LbQvdC+INC70Lgg0YDQsNGB0YjQuNGA0LjRgtGMINGA0Y/QtC4g0KDQsNGB0YjQuNGA0Y/RgtGMINGA0Y/QtCDRgdGC0L7QuNGCINC/0YDQuCDRgdGC0L7RhdCw0YHRgtC40YfQtdGB0LrQvtC8INGC0YDQtdC90LTQtSAoQXV0b3JlZ3Jlc3NpdmUgZXh0ZW5zaW9uIChkZWZhdWx0KS4gSXQgaXMgaW5kaWNhdGVkIGZvciBzdGF0aW9uYXJ5IGFuZCBzdG9jaGFzdGljIHRyZW5kIHRpbWUgc2VyaWVzIGFzIHdlbGwpLiDQoNC10LDQu9C40LfQvtCy0LDQvdC+INGC0L7Qu9GM0LrQviBBdXRvcmVncmVzc2l2ZSBleHRlbnNpb24uDQoNClwNCtCd0LAg0LLRi9GF0L7QtNC1INGB0L/QuNGB0L7QuiDQstGL0LTQsNGR0YLRgdGPINGB0L/QuNGB0L7QuiBsaXN0KHRfc2VyaWVzLCBpbXBvcnRhbmNlKS5cDQp0X3NlcmllcyDigJQg0LzQsNGC0YDQuNGG0LAsINC/0L4g0YHRgtC+0LvQsdGG0LDQvCDQutC+0YLQvtGA0L7QuSDRgNCw0YHQv9C+0LvQsNCz0LDRjtGC0YHRjyDQstGA0LXQvNC10L3QvdGL0LUg0YDRj9C00YssINC+0YLQstC10YfQsNGO0YnQuNC1INC30LAg0YfQsNGB0YLQvtGC0YsgKGktMSkvTCwg0LPQtNC1IGkg4oCUINC90L7QvNC10YAg0YHRgtC+0LvQsdGG0LAsIEwg4oCUINC00LvQuNC90LAg0L7QutC90LAuXA0KaW1wb3J0YW5jZSDigJQg0LLQtdC60YLQvtGALCDQvtGC0LLQtdGH0LDRjtGJ0LjQuSDQt9CwINC30L3QsNGH0LjQvNC+0YHRgtGMIGkt0L7Qs9C+INCy0YDQtdC80LXQvdC90L7Qs9C+INGA0Y/QtNCwINCyINGA0LDQt9C70L7Qu9C20LXQvdC40LguINCn0LXQvCDQsdC+0LvRjNGI0LUg0LfQvdCw0YfQtdC90LjQtSwg0YLQtdC8INCx0L7Qu9GM0YjQuNC5INCy0LrQu9Cw0LQg0LLQvdGR0YEgaS3RgtGL0Lkg0LLRgNC10LzQtdC90L3QvtC5INGA0Y/QtC4NCg0KYGBge3J9DQpjaXJjdWxhbnRfU1NBIDwtIGZ1bmN0aW9uKHRzLCBMID0gTlVMTCwgZXh0ZW5kX2ZsYWcgPSBGQUxTRSl7DQogIHRpbWVfc2VyaWVzIDwtIHRzDQogICMgQ29uc3RydWN0IHRyYWplY3RvcnkgbWF0cml4DQogIE4gPC0gbGVuZ3RoKHRpbWVfc2VyaWVzKQ0KICBpZiAoaXMubnVsbChMKSl7DQogICAgTCA8LSAoTiArIDEpJS8lMg0KICB9DQogICMg0J/RgNC+0LLQtdGA0LrQsCDQvdCwINGA0LDRgdGI0LjRgNC10L3QuNGPINGA0Y/QtNCwDQogIGlmIChleHRlbmRfZmxhZyA9PSBGQUxTRSl7DQogICAgSCA8LSAwDQogICAgdGltZV9zZXJpZXMgPC0gdHMNCiAgfQ0KICBlbHNlew0KICAgIEggPC0gTA0KICAgIHRpbWVfc2VyaWVzIDwtIGV4dGVuZCh0cywgSCkNCiAgfQ0KICANCiAgWCA8LSBoYW5rZWwodGltZV9zZXJpZXMsIEwpDQogIA0KICAjIE51bWJlciBvZiBzeW1tZXRyaWMgZnJlcXVlbmN5IHBhaXJzIGFyb3VuZCAxLzINCiAgaWYgKEwgJSUgMikgew0KICAgIG5mMiA8LSAoTCArIDEpIC8gMiAtIDENCiAgfSBlbHNlIHsNCiAgICBuZjIgPC0gTCAvIDIgLSAxDQogIH0NCiAgDQogICMgTnVtYmVyIG9mIGZyZXF1ZW5jaWVzIDw9IDEvMg0KICBuZnQgPC0gbmYyICsgYWJzKChMICUlIDIpIC0gMikNCiAgDQogICMgRGVjb21wb3NpdGlvbg0KICAjIEVzdGltYXRlIGF1dG9jb3ZhcmlhbmNlICAgICBPSw0KICBhdXRvY292IDwtIG51bWVyaWMoTCkNCiAgZm9yIChtIGluIDA6KEwtMSkpew0KICAgIGF1dG9jb3ZbW20rMV1dIDwtIHN1bSh0aW1lX3Nlcmllc1sxOihOLW0pXSAqIHRpbWVfc2VyaWVzWygxK20pOk5dKSAvIChOLW0pDQogIH0NCiAgDQogICMgRmlyc3Qgcm93IG9mIGNpcmN1bGFudCBtYXRyaXgNCiAgY2lyY19maXJzdF9yb3cgPC0gbnVtZXJpYyhMKQ0KICBmb3IgKG0gaW4gMDooTC0xKSl7DQogICAgY2lyY19maXJzdF9yb3dbW20rMV1dIDwtIChMLW0pL0wgKiBhdXRvY292W1ttKzFdXSArIChtKS9MICogYXV0b2NvdltbTC1tXV0NCiAgfQ0KICANCiAgIyBCdWlsZCBjaXJjdWxhbnQgbWF0cml4DQogIFNfQyA8LSBtYXRyaXgoY2lyY19maXJzdF9yb3csIG5yb3cgPSAxKQ0KICBzaGlmdGVkX3ZlY3RvciA8LSBjaXJjX2ZpcnN0X3Jvdw0KICBmb3IgKGkgaW4gMjooTCkpIHsNCiAgICBzaGlmdGVkX3ZlY3RvciA8LSBzaGlmdF92ZWN0b3Ioc2hpZnRlZF92ZWN0b3IpDQogICAgIyBTX0MgPC0gcmJpbmQoU19DLCBhcy52ZWN0b3Ioc2hpZnRlZF92ZWN0b3IpKQ0KICAgIFNfQyA8LSByYmluZChhcy52ZWN0b3Ioc2hpZnRlZF92ZWN0b3IpLCBTX0MpDQogIH0NCiAgDQogICMgRWlnZW52ZWN0b3JzIG9mIGNpcmN1bGFudCBtYXRyaXggKHVuaXRhcnkgYmFzZSkNCiAgVSA8LSBkZnRtdHgoTCkvc3FydChMKQ0KICANCiAgIyBSZWFsIGVpZ2VudmVjdG9ycyAob3J0aG9ub3JtYWwgYmFzZSkNCiAgVVssIDFdIDwtIFJlKFVbLCAxXSkNCiAgZm9yIChrIGluIDE6bmYyKSB7DQogICAgdV9rIDwtIFVbLCBrICsgMV0NCiAgICBVWywgayArIDFdIDwtIHNxcnQoMikgKiBSZSh1X2spDQogICAgVVssIEwgKyAyIC0gKGsgKyAxKV0gPC0gc3FydCgyKSAqIEltKHVfaykNCiAgfQ0KICBpZiAoTCAlJSAyICE9IDApIHsNCiAgICBVWywgbmZ0XSA8LSBSZShVWywgbmZ0XSkNCiAgfQ0KICANCiAgIyBFaWdlbnZhbHVlcyBvZiBjaXJjdWxhbnQgbWF0cml4OiBlc3RpbWF0ZWQgcG93ZXIgc3BlY3RyYWwgZGVuc2l0eQ0KICBwc2QgPC0gYWJzKGRpYWcodChVKSAlKiUgU19DICUqJSBVKSkNCiAgDQogICMgUHJpbmNpcGFsIGNvbXBvbmVudHMNCiAgVyA8LSB0KFUpICUqJSBYDQogICMgUmVjb25zdHJ1Y3Rpb24NCiAgIyBFbGVtZW50YXJ5IHJlY29uc3RydWN0ZWQgc2VyaWVzDQogIFIgPC0gbWF0cml4KDAsIG5yb3cgPSBOKzIqSCwgbmNvbCA9IEwpDQogIGZvciAoayBpbiAxOkwpIHsNCiAgICBSWywga10gPC0gVVsgLGtdICUqJSB0KFdbaywgXSkgfD4gZGlhZ19hdmVyYWdpbmcoKQ0KICB9DQogIA0KICAjIEdyb3VwaW5nIGJ5IGZyZXF1ZW5jeQ0KICAjIEVsZW1lbnRhcnkgcmVjb25zdHJ1Y3RlZCBzZXJpZXMgYnkgZnJlcXVlbmN5DQogIFogPC0gbWF0cml4KDAsIG5yb3cgPSBOKzIqSCwgbmNvbCA9IG5mdCkNCiAgWlssIDFdIDwtIFJbLCAxXQ0KICAjIEltcG9ydGFuY2Ugb2YgY29tcG9uZW50DQogIGltcCA8LSBudW1lcmljKG5mdCkNCiAgbGFtYmRhX3NtIDwtIHN1bShwc2QpDQogIGltcFsxXSA8LSBwc2RbMV0vbGFtYmRhX3NtDQogIGZvciAoayBpbiAxOm5mMikgew0KICAgIFpbLCBrICsgMV0gPC0gUlssIGsgKyAxXSArIFJbLCBMICsgMiAtIChrICsgMSldDQogICAgaW1wW2srMV0gPC0gKHBzZFtrKzFdICsgcHNkWyBMICsgMiAtIChrICsgMSldKS9sYW1iZGFfc20NCiAgfQ0KICBpZiAoTCAlJSAyICE9IDApIHsNCiAgICBaWywgbmZ0XSA8LSBSWywgbmZ0XQ0KICAgIGltcFtuZnRdIDwtIHBzZFtuZnRdIC8gbGFtYmRhX3NtDQogIH0NCiAgDQogIGxpc3QodF9zZXJpZXMgPSBaWyhIKzEpOihOK0gpLF0sDQogICAgICAgaW1wb3J0YW5jZSA9IGltcCwNCiAgICAgICBmcmVxID0gKDA6KGxlbmd0aChpbXApIC0xKSkvTA0KICAgICAgICkNCn0NCmBgYA0KDQpgYGB7cn0NCiMgZ3JvdXBzIC0gbGlzdCBvZiBmcmVxdWVuY2llcw0KZ3JvdXBpbmdfY2lzc2EgPC0gZnVuY3Rpb24oY2lzc2FfcmVzLCBncm91cHMpew0KICBmcmVxIDwtIGNpc3NhX3JlcyRmcmVxDQogIHRfc2VyaWVzIDwtIGNpc3NhX3JlcyR0X3Nlcmllcw0KICANCiAgDQogIHJlc2lkdWFscyA8LSAwDQogIHJlc3VsdCA8LSBzZXROYW1lcyhhcy5saXN0KHJlcCgwLCBsZW5ndGgoZ3JvdXBzKSkpLCBuYW1lcyhncm91cHMpKQ0KICByZXN1bHRfZnJlcXMgPC0gbGlzdCgpDQogIGZvciAoaSBpbiAxOmxlbmd0aChjaXNzYV9yZXMkZnJlcSkpew0KICAgIGZsYWcgPC0gRkFMU0UNCiAgICBmb3IgKG5hbWUgaW4gbmFtZXMoZ3JvdXBzKSl7DQogICAgICBpZiAoZ3JvdXBzW1tuYW1lXV1bMV0gPD0gZnJlcVtpXSAmIGZyZXFbaV0gPD0gZ3JvdXBzW1tuYW1lXV1bMl0pew0KICAgICAgICBmbGFnIDwtIFRSVUUNCiAgICAgICAgcmVzdWx0W1tuYW1lXV0gPC0gcmVzdWx0W1tuYW1lXV0gKyB0X3Nlcmllc1ssIGldDQogICAgICAgIHJlc3VsdF9mcmVxc1tbbmFtZV1dIDwtIGMocmVzdWx0X2ZyZXFzW1tuYW1lXV0sIGZyZXFbaV0pDQogICAgICB9DQogICAgfQ0KICAgIA0KICAgIGlmIChmbGFnID09IEZBTFNFKXsNCiAgICAgIHJlc2lkdWFscyA8LSByZXNpZHVhbHMgKyB0X3Nlcmllc1ssIGldDQogICAgfQ0KICB9DQogIA0KICByZXN1bHRbWyJyZXNpZHVhbHMiXV0gPC0gcmVzaWR1YWxzDQogIA0KICByZXR1cm4oDQogICAgbGlzdCgNCiAgICAgIHRfc2VyaWVzID0gcmVzdWx0LA0KICAgICAgZnJlcXNfYnlfZ3JvdXAgPSByZXN1bHRfZnJlcXMNCiAgICApDQogICkNCiAgcmVzdWx0DQp9DQpgYGANCg0KYGBge3J9DQpnZW5lcmF0ZV90cyA8LSBmdW5jdGlvbihmdW5jLCBuPTFlMywgLi4uKXsNCiAgMTpuIHw+IGZ1bmMoLi4uKSB8PiB0cygpDQp9DQoNCmZfY29zIDwtIGZ1bmN0aW9uKHgsIEEgPSAxLCBvbWVnYSA9IDEvNCwgcGhpID0gMCl7DQogIGZfZXhwX21vZF9oYXJtX3Nlcmllcyh4LCBBLCBhbHBoYSA9IDAsIG9tZWdhID0gb21lZ2EsIHBoaSA9IHBoaSkNCn0NCg0KZl9zaW4gPC0gZnVuY3Rpb24oeCwgQSA9IDEsIG9tZWdhID0gMS80LCBwaGkgPSAzKnBpLzIpew0KICBmX2V4cF9tb2RfaGFybV9zZXJpZXMoeCwgQSwgYWxwaGEgPSAwLCBvbWVnYSA9IG9tZWdhLCBwaGkgPSBwaGkpDQp9DQoNCmZfZXhwIDwtIGZ1bmN0aW9uKHgsIEEgPSAxLCBhbHBoYSA9IDEpew0KICBBICogZXhwKGFscGhhICogeCkNCn0NCg0KZl9leHBfY29zIDwtIGZ1bmN0aW9uKHgsIEEgPSAxLCBhbHBoYSA9IDEsIG9tZWdhID0gMS80LCBwaGkgPSAwKXsNCiAgZl9leHBfbW9kX2hhcm1fc2VyaWVzKHgsIEEsIGFscGhhLCBvbWVnYSwgcGhpKQ0KfQ0KDQpmX2NvbnN0IDwtIGZ1bmN0aW9uKHgsIEMgPSAwKXsNCiAgcmVwKEMsIGxlbmd0aCh4KSkNCn0NCg0KZl9leHBfbW9kX2hhcm1fc2VyaWVzIDwtIGZ1bmN0aW9uKHgsIEEgPSAxLCBhbHBoYSA9IDEsIG9tZWdhID0gMS80LCBwaGkgPSAwKXsNCiAgQSpleHAoYWxwaGEqeCkqY29zKDIqcGkqb21lZ2EqeCArIHBoaSkNCn0NCg0KZl9saW5lYXIgPC0gZnVuY3Rpb24oeCwgYSA9IDEsIGIgPSAwKXsNCiAgYSp4ICsgYg0KfQ0KbXNlIDwtIGZ1bmN0aW9uKGZfdHJ1ZSwgZl9yZWNvbnN0cnVjdGVkKXsNCiAgIG1lYW4oKGZfdHJ1ZSAtIGZfcmVjb25zdHJ1Y3RlZCleMikgDQp9DQpgYGANCg0KIyMjIyDQntGI0LjQsdC60LAg0L/RgNC4IEx3IGluIE4sIEt3IG5vdCBpbiBODQoNCmBgYHtyfQ0KbiA8LSA5NioyKzUNCkwgPC0gOTYNCmVwcyA8LSAxLzk3DQpmX3N1bSA8LSBmdW5jdGlvbih4KXsNCiAgZl9jb25zdCh4LCBDID0gMSkgKyBmX2Nvcyh4LCBvbWVnYSA9IDEvMTIpIA0KfQ0KDQoNCmZfY29uc3QgfD4gZ2VuZXJhdGVfdHMobiwgQyA9IDEpIHw+DQogIHBsb3QoY29sID0gImdyZWVuIiwgeWxpbSA9IGMoLTEsIDIpLCB5bGFiID0gImZfbiIpDQpmX2NvcyB8Pg0KICBnZW5lcmF0ZV90cyhuLCBvbWVnYSA9IDEvMTIpIHw+DQogIGxpbmVzKGNvbD0iZ3JlZW4iKQ0KZl9zdW0gfD4gZ2VuZXJhdGVfdHMobikgfD4gbGluZXMobHdkID0gMywgY29sPSdyZWQnKQ0KZl9uIDwtIGZfc3VtKDE6bikNCg0KDQoNCmMgPC0gY2lyY3VsYW50X1NTQShmX24sIEwgPSA5NiwgZXh0ZW5kX2ZsYWcgPSBGQUxTRSkNCnIgPC0gZ3JvdXBpbmdfY2lzc2EoYywNCiAgICAgICAgICAgICAgIGdyb3VwcyA9IGxpc3QoDQogICAgICAgICAgICAgICAgIHRyZW5kID0gYygwLCBlcHMpLA0KICAgICAgICAgICAgICAgICBzZXNvbmFsID0gYygxLzEyLWVwcywgMS8xMiArIGVwcykNCiAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICkkdF9zZXJpZXMNCg0KZl9DIDwtIGZfY29uc3QgfD4gZ2VuZXJhdGVfdHMobiwgQyA9IDEpDQpmX2MgPC0gZl9jb3MgfD4gZ2VuZXJhdGVfdHMobiwgb21lZ2EgPSAxLzEyKQ0KcHJpbnQoItCe0YjQuNCx0LrQuCDQv9GA0LggQ2lTU0EiKQ0KcHJpbnQocGFzdGUoItCe0YjQuNCx0LrQsCDQv9GA0Lgg0LLRi9GH0LjRgdC70LXQvdC40LggQyA9IDE6ICIsIG1zZShmX0MsIHIkdHJlbmQpIHw+IGZvcm1hdChzY2llbnRpZmljID0gVFJVRSwgZGlnaXRzID0gMikgKSkNCnByaW50KHBhc3RlKCLQntGI0LjQsdC60LAg0L/RgNC4INCy0YvRh9C40YHQu9C10L3QuNC4IGNvcyhwaS8xMik6ICIsIG1zZShmX2MsIHIkc2Vzb25hbCkgfD4gZm9ybWF0KHNjaWVudGlmaWMgPSBUUlVFLCBkaWdpdHMgPSAyKSApKQ0KDQpsaW5lcygxOm4sIHIkdHJlbmQsIGNvbD0iYmx1ZSIpDQpsaW5lcygxOm4sIHIkc2Vzb25hbCwgY29sPSJibHVlIikNCg0KZl9jb25zdCB8PiBnZW5lcmF0ZV90cyhuLCBDID0gMSkgfD4NCiAgcGxvdChjb2wgPSAiZ3JlZW4iLCB5bGltID0gYygtMSwgMiksIHlsYWIgPSAiZl9uIikNCmZfY29zIHw+DQogIGdlbmVyYXRlX3RzKG4sIG9tZWdhID0gMS8xMikgfD4NCiAgbGluZXMoY29sPSJncmVlbiIpDQpmX3N1bSB8PiBnZW5lcmF0ZV90cyhuKSB8PiBsaW5lcyhsd2QgPSAzLCBjb2w9J3JlZCcpDQpmX24gPC0gZl9zdW0oMTpuKQ0KDQpzIDwtIHNzYShmX24sIEwgPSA5NikNCnIgPC0gcmVjb25zdHJ1Y3QocywgZ3JvdXBzPWxpc3QoDQogIHRyZW5kID0gMSwNCiAgc2Vzb25hbCA9IDI6Mw0KKSkNCg0KDQpwcmludCgi0J7RiNC40LHQutC4INC/0YDQuCBTU0EiKQ0KcHJpbnQocGFzdGUoItCe0YjQuNCx0LrQsCDQv9GA0Lgg0LLRi9GH0LjRgdC70LXQvdC40LggQyA9IDE6ICIsIG1zZShmX0MsIHIkdHJlbmQpIHw+IGZvcm1hdChzY2llbnRpZmljID0gVFJVRSwgZGlnaXRzID0gMikgICkpDQpwcmludChwYXN0ZSgi0J7RiNC40LHQutCwINC/0YDQuCDQstGL0YfQuNGB0LvQtdC90LjQuCBjb3MocGkvMTIpOiAiLCBtc2UoZl9jLCByJHNlc29uYWwpIHw+IGZvcm1hdChzY2llbnRpZmljID0gVFJVRSwgZGlnaXRzID0gMikpKQ0KDQpsaW5lcygxOm4sIHIkdHJlbmQpDQpsaW5lcygxOm4sIHIkc2Vzb25hbCkNCmBgYA0KDQojIyMjINCf0YDQvtCy0LXRgNC60LAg0YDQsNC30LTQtdC70LjQvNC+0YHRgtC4INC90LXQv9C10YDQuNC+0LTQuNGH0LXRgdC60LjRhSDQutC+0LzQv9C+0L3QtdC90YIgKyDQsNCy0YLQvtCz0YDRg9C/0L/QuNGA0L7QstC60LAgU1NBDQoNCmBgYHtyfQ0KbiA8LSA5NioyLTENCkwgPC0gOTYNCmVwcyA8LSAxLzk3DQoNCkMgPC0gMQ0Kb21lZ2FfY3MgPC0gMS8xMg0Kb21lZ2Ffc24gPC0gMS8yNA0KYSA8LSAxLzEwMA0KZl9zdW0gPC0gZnVuY3Rpb24oeCl7DQogIGZfY29uc3QoeCwgQyA9IEMpICsNCiAgICBmX2Nvcyh4LCBvbWVnYSA9IG9tZWdhX2NzKSArDQogICAgZl9leHAoeCwgYSA9IGEpICsNCiAgICBmX3Npbih4LCBvbWVnYSA9IG9tZWdhX3NuKQ0KfQ0KDQoNCmZfQyA8LSBmX2NvbnN0IHw+IGdlbmVyYXRlX3RzKG4sIEMgPSBDKQ0KZl9jIDwtIGZfY29zIHw+IGdlbmVyYXRlX3RzKG4sIG9tZWdhID0gb21lZ2FfY3MpDQpmX3MgPC0gZl9zaW4gfD4gZ2VuZXJhdGVfdHMobiwgb21lZ2EgPSBvbWVnYV9zbikNCmZfZSA8LSBmX2V4cCB8PiBnZW5lcmF0ZV90cyhuLCBhID0gYSkNCg0KZl9uIDwtIGZfc3VtKDE6bikNCg0KbGlicmFyeSh4dGFibGUpDQoNCiMg0KjQsNCzIDI6INCh0L7Qt9C00LDQvdC40LUg0L/RgNC40LzQtdGA0LAg0LTQsNC90L3Ri9GFDQpkYXRhIDwtIGRhdGEuZnJhbWUoDQogINCc0LXRgtC+0LQgPSBjKCJTU0EiLCAiQ2lTU0EiKSwNCiAgZV9lcnIgPSBjKDIwLCAyMCksDQogIGNfZXJyID0gYygyMywgMzUpLA0KICBlY19lcnIgPSBjKDIwLCAyMCksDQogIHNpbl9lcnIgPSBjICgyMCwgMjApLA0KICBjb3NfZXJyID0gYygxLCAxKQ0KKQ0KDQoNCiMg0J7RgtGA0LjRgdC+0LLQutCwINGA0Y/QtNCwIGZfbg0KcGxvdChmX24sIHR5cGUgPSAibCIsIGx3ZCA9IDMsIGNvbCA9ICdyZWQnLCB5bGltID0gYygtMiwgMTApLA0KICAgICB4bGFiID0gItCS0YDQtdC80Y8iLCB5bGFiID0gItCX0L3QsNGH0LXQvdC40Y8g0YDRj9C00LAiLCBtYWluID0gItCg0LDQt9C70L7QttC10L3QuNC1INCy0YDQtdC80LXQvdC90L7Qs9C+INGA0Y/QtNCwIikNCg0KIyDQlNC+0LHQsNCy0LvQtdC90LjQtSDQvtGC0LTQtdC70YzQvdGL0YUg0LrQvtC80L/QvtC90LXQvdGC0L7QsiAoZl9DLCBmX2MsIGZfZSkNCmxpbmVzKGZfQywgY29sID0gImJsdWUiKSAgIyDQmtC+0LzQv9C+0L3QtdC90YIgZl9DDQpsaW5lcyhmX2MsIGNvbCA9ICJibHVlIikgICMg0JrQvtC80L/QvtC90LXQvdGCIGZfYw0KbGluZXMoZl9lLCBjb2wgPSAiYmx1ZSIpICAjINCa0L7QvNC/0L7QvdC10L3RgiBmX2UNCmxpbmVzKGZfcywgY29sID0gImJsdWUiKQ0KDQojINCb0LXQs9C10L3QtNCwDQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQgPSBjKCLQktC10YHRjCDRgNGP0LQiLCAi0JrQvtC80L/QvtC90LXQvdGC0YsiKSwgDQogICAgICAgY29sID0gYygicmVkIiwgImJsdWUiKSwgbHR5ID0gMSwgbHdkID0gMykNCg0KDQoNCg0KDQoNCg0KDQpjIDwtIGNpcmN1bGFudF9TU0EoZl9uLCBMID0gTCwgZXh0ZW5kX2ZsYWcgPSBUUlVFKQ0KIyByIDwtIGMkdF9zZXJpZXMNCnIgPC0gZ3JvdXBpbmdfY2lzc2EoYywNCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBzID0gbGlzdCgNCiAgICAgICAgICAgICAgICAgICAgICAjIHRyZW5kID0gYygwLCAxLzEwMCksDQogICAgICAgICAgICAgICAgICAgICAgdHJlbmQgPSBjKDAsIGVwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMjQgLSBlcHMsIDEvMjQrZXBzKQ0KICAgICAgICAgICAgICAgICAgICApKSR0X3Nlcmllcw0KDQpkYXRhJGNvc19lcnJbMl0gPC0gbXNlKGZfcywgciRzZXNvbmFsX3NpbikgfD4gZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJHNpbl9lcnJbMl0gPC0gbXNlKGZfYywgciRzZXNvbmFsX2NvcykgfD4gZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJGVjX2VyclsyXSA8LSBtc2UoZl9DK2ZfZSwgciR0cmVuZCkgfD4gZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQoNCg0KIyBwbmcoIkM6L1VzZXJzL25pazFtL0Rlc2t0b3Av0YPQvdC40LovNiDRgdC10Lwv0LrRg9GA0YHQsNGHL9Ci0LXQutGB0YIg0YDQsNCx0L7RgtGLL2ltZy90cmVuZCBpbnNlcGFyYWJpbGl0eS9DaVNTQS5wbmciKSAgIyDRgdC+0YXRgNCw0L3QtdC90LjQtSDQsiDRhNC+0YDQvNCw0YLQtSBQTkcNCg0KcGxvdCgxOm4sIGZfbiwgdHlwZSA9ICJsIiwgbHdkPTMsIHlsaW09IGMoLTIsIDEwKSwgY29sPSJyZWQiLA0KICAgICB4bGFiID0gItCS0YDQtdC80Y8iLCB5bGFiID0gItCX0L3QsNGH0LXQvdC40Y8g0YDRj9C00LAiLCBtYWluID0gIkNpU1NBINGA0LDQt9C70L7QttC10L3QuNC1INCy0YDQtdC80LXQvdC90L7Qs9C+INGA0Y/QtNCwIikNCmxpbmVzKDE6biwgciR0cmVuZCwgY29sID0gImJsdWUiKQ0KbGluZXMoMTpuLCByJHNlc29uYWxfc2luLCBjb2wgPSAiYmx1ZSIpDQpsaW5lcygxOm4sIHIkc2Vzb25hbF9jb3MsIGNvbCA9ICJibHVlIikNCg0KIyDQm9C10LPQtdC90LTQsA0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kID0gYygi0JLQtdGB0Ywg0YDRj9C0IiwgItCa0L7QvNC/0L7QvdC10L3RgtGLIiksIA0KICAgICAgIGNvbCA9IGMoInJlZCIsICJibHVlIiksIGx0eSA9IDEsIGx3ZCA9IDMpDQoNCiMgZGV2Lm9mZigpICAjINC30LDQstC10YDRiNC10L3QuNC1INGB0L7RhdGA0LDQvdC10L3QuNGPDQoNCg0KDQoNCg0KDQoNCg0KDQoNCnMgPC0gc3NhKGZfbiwgTCkNCiMgZSA8LSBlb3NzYV9uZXcocywgbmVzdGVkLmdyb3VwcyA9IGxpc3QoMTozMCksIGNsdXN0X3R5cGUgPSAiZGlzdGFuY2UiKQ0KZSA8LSBlb3NzYShzLCAxOjEwLCBrID0gNykNCg0KZ19zZXNvbmFsIDwtIGdyb3VwaW5nLmF1dG8oZSwgYmFzZSA9ICJlaWdlbiIsDQogICAgICAgICAgICAgICAgICAgZnJlcS5iaW5zID0gbGlzdCh0cmVuZCA9IGMoZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWwyID0gYygxLzI0LWVwcywgMS8yNCtlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbDEgPSBjKDEvMTItZXBzLCAxLzEyK2VwcykNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICAgICAgdGhyZXNob2xkID0gMC4xKQ0KDQoNCnIgPC0gUnNzYTo6cmVjb25zdHJ1Y3QoZSwgZ3JvdXBzPWMobGlzdChleHAgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDID0gMg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnX3Nlc29uYWwpDQogICAgICAgICAgICAgICAgICkNCg0KcGxvdCh3Y29yKGUsIGdyb3VwcyA9IDE6MjQpLCBzY2FsZXMgPSBsaXN0KGF0ID0gYygxMCwgMjAsIDMwKSkpDQoNCmRhdGEkY19lcnJbMV0gPC0gbXNlKGZfQywgciRDKSB8PiBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkZV9lcnJbMV0gPC0gbXNlKGZfZSwgciRleHApIHw+IGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRjb3NfZXJyWzFdIDwtIG1zZShmX2MsIHIkc2Vzb25hbDEpIHw+IGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRzaW5fZXJyWzFdIDwtIG1zZShmX3MsIHIkc2Vzb25hbDIpIHw+IGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRlY19lcnJbMV0gPC0gbXNlKGZfQytmX2UsIHIkQytyJGV4cCkgfD4gZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQoNCg0KIyBwbmcoIkM6L1VzZXJzL25pazFtL0Rlc2t0b3Av0YPQvdC40LovNiDRgdC10Lwv0LrRg9GA0YHQsNGHL9Ci0LXQutGB0YIg0YDQsNCx0L7RgtGLL2ltZy90cmVuZCBpbnNlcGFyYWJpbGl0eS9TU0EucG5nIikgICMg0YHQvtGF0YDQsNC90LXQvdC40LUg0LIg0YTQvtGA0LzQsNGC0LUgUE5HDQoNCnBsb3QoMTpuLCBmX24sIHR5cGUgPSAibCIsIGx3ZD0zLCB5bGltPSBjKC0yLCAxMCksIGNvbD0icmVkIiwNCiAgICAgeGxhYiA9ICLQktGA0LXQvNGPIiwgeWxhYiA9ICLQl9C90LDRh9C10L3QuNGPINGA0Y/QtNCwIiwgbWFpbiA9ICJTU0Eg0YDQsNC30LvQvtC20LXQvdC40LUg0LLRgNC10LzQtdC90L3QvtCz0L4g0YDRj9C00LAiKQ0KDQpsaW5lcygxOm4sIHIkdHJlbmQsIHR5cGUgPSAibCIsIGNvbD0iZ3JlZW4iKQ0KbGluZXMoMTpuLCByJGV4cCwgdHlwZSA9ICJsIiwgeWxpbT0gYygtMiwgMTApLCBjb2w9ImJsdWUiKQ0KbGluZXMoMTpuLCByJEMsIGNvbCA9ICJibHVlIikNCmxpbmVzKDE6biwgciRzZXNvbmFsMSwgY29sID0gImJsdWUiKQ0KbGluZXMoMTpuLCByJHNlc29uYWwyLCBjb2wgPSAiYmx1ZSIpDQoNCiMg0JvQtdCz0LXQvdC00LANCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZCA9IGMoItCS0LXRgdGMINGA0Y/QtCIsICLQmtC+0LzQv9C+0L3QtdC90YLRiyIpLCANCiAgICAgICBjb2wgPSBjKCJyZWQiLCAiYmx1ZSIpLCBsdHkgPSAxLCBsd2QgPSAzKQ0KDQoNCg0KDQoNCg0KDQojINCo0LDQsyAzOiDQn9GA0LXQvtCx0YDQsNC30L7QstCw0L3QuNC1INC00LDQvdC90YvRhSDQsiDRhNC+0YDQvNCw0YIgTGFUZVgNCnRhYmxlX2xhdGV4IDwtIHh0YWJsZShkYXRhLCBjYXB0aW9uID0gIkV4YW1wbGUgVGFibGUiKQ0KDQojINCo0LDQsyA0OiDQktGL0LLQvtC0INGC0LDQsdC70LjRhtGLINCyIExhVGVYINGE0LDQudC7DQpwcmludCh0YWJsZV9sYXRleCwgaW5jbHVkZS5yb3duYW1lcyA9IEZBTFNFKQ0KDQoNCg0KDQoNCmBgYA0KDQojIyMjINCf0YDQuNC80LXRgCBjb3NcKmV4cA0KDQpgYGB7cn0NCm4gPC0gOTYqMi0xDQpMIDwtIDk2DQplcHMgPC0gMS8oTCsxKQ0KDQpDIDwtIDENCm9tZWdhX2NzIDwtIDEvMTINCm9tZWdhX3NuIDwtIDEvMjQNCmEgPC0gMS8xMDANCm9tZWdhX2V4cCA8LSAxLzQ4DQpmX3N1bSA8LSBmdW5jdGlvbih4KXsNCiAgICBmX2Nvcyh4LCBvbWVnYSA9IG9tZWdhX2NzKSArDQogICAgZl9leHBfbW9kX2hhcm1fc2VyaWVzKHgsIGEgPSBhLCBvbWVnYSA9IG9tZWdhX2V4cCkgKw0KICAgIGZfc2luKHgsIG9tZWdhID0gb21lZ2Ffc24pIA0KfQ0KDQoNCmZfYyA8LSBmX2NvcyB8PiBnZW5lcmF0ZV90cyhuLCBvbWVnYSA9IG9tZWdhX2NzKQ0KZl9zIDwtIGZfc2luIHw+IGdlbmVyYXRlX3RzKG4sIG9tZWdhID0gb21lZ2Ffc24pDQpmX2UgPC0gZl9leHBfbW9kX2hhcm1fc2VyaWVzIHw+IGdlbmVyYXRlX3RzKG4sIGEgPSBhLCBvbWVnYSA9IG9tZWdhX2V4cCkNCg0KZl9uIDwtIGZfc3VtKDE6bikNCg0KbGlicmFyeSh4dGFibGUpDQoNCiMg0KjQsNCzIDI6INCh0L7Qt9C00LDQvdC40LUg0L/RgNC40LzQtdGA0LAg0LTQsNC90L3Ri9GFDQpkYXRhIDwtIGRhdGEuZnJhbWUoDQogINCc0LXRgtC+0LQgPSBjKCJTU0EiLCAiQ2lTU0EiKSwNCiAgZXhwX2VyciA9IGMoMjAsIDIwKSwNCiAgc2luX2VyciA9IGMgKDIwLCAyMCksDQogIGNvc19lcnIgPSBjKDEsIDEpDQopDQoNCg0KIyDQntGC0YDQuNGB0L7QstC60LAg0YDRj9C00LAgZl9uDQpwbG90KGZfbiwgdHlwZSA9ICJsIiwgbHdkID0gMywgY29sID0gJ3JlZCcsIHlsaW0gPSBjKC0xMCwgMTApLA0KICAgICB4bGFiID0gItCS0YDQtdC80Y8iLCB5bGFiID0gItCX0L3QsNGH0LXQvdC40Y8g0YDRj9C00LAiLCBtYWluID0gItCg0LDQt9C70L7QttC10L3QuNC1INCy0YDQtdC80LXQvdC90L7Qs9C+INGA0Y/QtNCwIikNCg0KIyDQlNC+0LHQsNCy0LvQtdC90LjQtSDQvtGC0LTQtdC70YzQvdGL0YUg0LrQvtC80L/QvtC90LXQvdGC0L7QsiAoZl9DLCBmX2MsIGZfZSkNCmxpbmVzKGZfYywgY29sID0gImJsdWUiKSAgIyDQmtC+0LzQv9C+0L3QtdC90YIgZl9jDQpsaW5lcyhmX2UsIGNvbCA9ICJibHVlIikgICMg0JrQvtC80L/QvtC90LXQvdGCIGZfZQ0KbGluZXMoZl9zLCBjb2wgPSAiYmx1ZSIpDQoNCiMg0JvQtdCz0LXQvdC00LANCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZCA9IGMoItCS0LXRgdGMINGA0Y/QtCIsICLQmtC+0LzQv9C+0L3QtdC90YLRiyIpLCANCiAgICAgICBjb2wgPSBjKCJyZWQiLCAiYmx1ZSIpLCBsdHkgPSAxLCBsd2QgPSAzKQ0KDQoNCg0KDQoNCg0KDQoNCmMgPC0gY2lyY3VsYW50X1NTQShmX24sIEwgPSBMLCBleHRlbmRfZmxhZyA9IFRSVUUpDQojIHIgPC0gYyR0X3Nlcmllcw0KciA8LSBncm91cGluZ19jaXNzYShjLA0KICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgIHRyZW5kID0gYygwLCAxLzI2LWVwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMjQtZXBzLCAxLzI0K2VwcykNCiAgICAgICAgICAgICAgICAgICAgKSkkdF9zZXJpZXMNCg0KZGF0YSRjb3NfZXJyWzJdIDwtIG1zZShmX3MsIHIkc2Vzb25hbF9zaW4pIHw+IGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRzaW5fZXJyWzJdIDwtIG1zZShmX2MsIHIkc2Vzb25hbF9jb3MpIHw+IGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRleHBfZXJyWzJdIDwtIG1zZShmX2UsIHIkdHJlbmQpIHw+IGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KDQoNCiMgcG5nKCJDOi9Vc2Vycy9uaWsxbS9EZXNrdG9wL9GD0L3QuNC6LzYg0YHQtdC8L9C60YPRgNGB0LDRhy/QotC10LrRgdGCINGA0LDQsdC+0YLRiy9pbWcvdHJlbmQgaW5zZXBhcmFiaWxpdHkvQ2lTU0EucG5nIikgICMg0YHQvtGF0YDQsNC90LXQvdC40LUg0LIg0YTQvtGA0LzQsNGC0LUgUE5HDQoNCnBsb3QoMTpuLCBmX24sIHR5cGUgPSAibCIsIGx3ZD0zLCB5bGltPSBjKC0xMCwgMTApLCBjb2w9InJlZCIsDQogICAgIHhsYWIgPSAi0JLRgNC10LzRjyIsIHlsYWIgPSAi0JfQvdCw0YfQtdC90LjRjyDRgNGP0LTQsCIsIG1haW4gPSAiQ2lTU0Eg0YDQsNC30LvQvtC20LXQvdC40LUg0LLRgNC10LzQtdC90L3QvtCz0L4g0YDRj9C00LAiKQ0KbGluZXMoMTpuLCByJHRyZW5kLCBjb2wgPSAiYmx1ZSIpDQpsaW5lcygxOm4sIHIkc2Vzb25hbF9zaW4sIGNvbCA9ICJibHVlIikNCmxpbmVzKDE6biwgciRzZXNvbmFsX2NvcywgY29sID0gImJsdWUiKQ0KDQojINCb0LXQs9C10L3QtNCwDQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQgPSBjKCLQktC10YHRjCDRgNGP0LQiLCAi0JrQvtC80L/QvtC90LXQvdGC0YsiKSwgDQogICAgICAgY29sID0gYygicmVkIiwgImJsdWUiKSwgbHR5ID0gMSwgbHdkID0gMykNCg0KIyBkZXYub2ZmKCkgICMg0LfQsNCy0LXRgNGI0LXQvdC40LUg0YHQvtGF0YDQsNC90LXQvdC40Y8NCg0KDQoNCg0KDQoNCg0KDQoNCg0KcyA8LSBzc2EoZl9uLCBMKQ0KZSA8LSBlb3NzYV9uZXcocywgbmVzdGVkLmdyb3VwcyA9IGxpc3QoMTozMCksIGNsdXN0X3R5cGUgPSAiZGlzdGFuY2UiKQ0KDQpnX3Nlc29uYWwgPC0gZ3JvdXBpbmcuYXV0byhlLCBiYXNlID0gImVpZ2VuIiwNCiAgICAgICAgICAgICAgICAgICBmcmVxLmJpbnMgPSBsaXN0KHRyZW5kID0gYygxLzI1LWVwcyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsMiA9IGMoMS8yNC1lcHMsIDEvMjQrZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWwxID0gYygxLzEyLWVwcywgMS8xMitlcHMpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgICAgICAgIHRocmVzaG9sZCA9IDAuMSkNCg0KDQpyIDwtIHJlY29uc3RydWN0KGUsIGdyb3Vwcz0gZ19zZXNvbmFsKQ0KDQpwbG90KHdjb3IoZSwgZ3JvdXBzID0gMToyNCksIHNjYWxlcyA9IGxpc3QoYXQgPSBjKDEwLCAyMCwgMzApKSkNCg0KZGF0YSRleHBfZXJyWzFdIDwtIG1zZShmX2UsIHIkdHJlbmQpICB8PiBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkY29zX2VyclsxXSA8LSBtc2UoZl9jLCByJHNlc29uYWwxKSB8PiBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2VyclsxXSA8LSBtc2UoZl9zLCByJHNlc29uYWwyKSB8PiBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCg0KDQojIHBuZygiQzovVXNlcnMvbmlrMW0vRGVza3RvcC/Rg9C90LjQui82INGB0LXQvC/QutGD0YDRgdCw0Ycv0KLQtdC60YHRgiDRgNCw0LHQvtGC0YsvaW1nL3RyZW5kIGluc2VwYXJhYmlsaXR5L1NTQS5wbmciKSAgIyDRgdC+0YXRgNCw0L3QtdC90LjQtSDQsiDRhNC+0YDQvNCw0YLQtSBQTkcNCg0KcGxvdCgxOm4sIGZfbiwgdHlwZSA9ICJsIiwgbHdkPTMsIHlsaW09IGMoLTEwLCAxMCksIGNvbD0icmVkIiwNCiAgICAgeGxhYiA9ICLQktGA0LXQvNGPIiwgeWxhYiA9ICLQl9C90LDRh9C10L3QuNGPINGA0Y/QtNCwIiwgbWFpbiA9ICJTU0Eg0YDQsNC30LvQvtC20LXQvdC40LUg0LLRgNC10LzQtdC90L3QvtCz0L4g0YDRj9C00LAiKQ0KDQpsaW5lcygxOm4sIHIkdHJlbmQsIHR5cGUgPSAibCIsIGNvbD0iYmx1ZSIpDQpsaW5lcygxOm4sIHIkc2Vzb25hbDEsIGNvbCA9ICJibHVlIikNCmxpbmVzKDE6biwgciRzZXNvbmFsMiwgY29sID0gImJsdWUiKQ0KDQojINCb0LXQs9C10L3QtNCwDQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQgPSBjKCLQktC10YHRjCDRgNGP0LQiLCAi0JrQvtC80L/QvtC90LXQvdGC0YsiKSwgDQogICAgICAgY29sID0gYygicmVkIiwgImJsdWUiKSwgbHR5ID0gMSwgbHdkID0gMykNCg0KDQoNCg0KDQoNCg0KIyDQqNCw0LMgMzog0J/RgNC10L7QsdGA0LDQt9C+0LLQsNC90LjQtSDQtNCw0L3QvdGL0YUg0LIg0YTQvtGA0LzQsNGCIExhVGVYDQp0YWJsZV9sYXRleCA8LSB4dGFibGUoZGF0YSwgY2FwdGlvbiA9ICJFeGFtcGxlIFRhYmxlIikNCg0KIyDQqNCw0LMgNDog0JLRi9Cy0L7QtCDRgtCw0LHQu9C40YbRiyDQsiBMYVRlWCDRhNCw0LnQuw0KcHJpbnQodGFibGVfbGF0ZXgsIGluY2x1ZGUucm93bmFtZXMgPSBGQUxTRSkNCg0KDQpgYGANCg0KIyMg0JTQsNC90L3Ri9C1IElQDQoNCmBgYHtyfQ0KbGlicmFyeShyZWFkeGwpDQpkYXRhIDwtIHJlYWRfZXhjZWwoIkRhdGEvSW50ZXJuYXRpb25hbF9GaW5hbmNpYWxfU3RhdGlzdGljc18ueGxzeCIpDQpkYXRhIHw+IGhlYWQoKQ0KYGBgDQoNCtCe0YLRgNC40YHQvtCy0LrQsCDQtNCw0L3QvdGL0YUgSVANCg0KYGBge3J9DQpkYXRlcyA8LSBzZXEoYXMuRGF0ZSgiMTk3MC0wMS0wMSIpLCBhcy5EYXRlKCIyMDE4LTEtMzAiKSwgYnkgPSAibW9udGgiKQ0KSVBfdmFsdWVzIDwtIGRhdGFbMiwgLWMoMSwgMildIHw+IGFzLmRvdWJsZSgpIA0KcGxvdChkYXRlcywgSVBfdmFsdWVzLCB0eXBlPSJsIikNCmBgYA0KDQojIyMjIENpc3NhDQoNCtCe0YLRgNC40YHQvtCy0LrQsCDRgtGA0LXQvdC00L7QstC+0Lkg0YHQvtGB0YLQsNCy0LvRj9GO0YnQtdC5INGH0ZHRgNC90YvQvCDRhtCy0LXRgtC+0LwsINC+0YHQvdC+0LLQvdC+0Lkg0LLRgNC10LzQtdC90L3QvtC5INGA0Y/QtCDigJQg0LrRgNCw0YHQvdGL0LwNCg0KYGBge3J9DQpkYXRhX3NsaWNlIDwtIDE6NTM3DQpkYXRlc19zbGljZSA8LSBkYXRlc1tkYXRhX3NsaWNlXQ0KSVBfdmFsdWVzX3NsaWNlIDwtIElQX3ZhbHVlc1tkYXRhX3NsaWNlXQ0KZXBzIDwtIDEvMTkzDQoNCmMgPC0gY2lyY3VsYW50X1NTQShJUF92YWx1ZXNfc2xpY2UsIEwgPSAxOTIsIGV4dGVuZF9mbGFnID0gVFJVRSkNCnIgPC0gYyR0X3Nlcmllcw0KciA8LSBncm91cGluZ19jaXNzYShjLA0KICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgIHRyZW5kID0gYygwLCAxLzE5MiksDQogICAgICAgICAgICAgICAgICAgICAgY3ljbGUgPSBjKDEvOTcsIDUvOTUpLA0KICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWwgPSBjKDEvMTMsIDEvMiswLjAwMDEpDQogICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0Kcl9zZXNvbmFsIDwtICBncm91cGluZ19jaXNzYShjLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgczEgPSBjKDE2LzE5MiAtIGVwcywgMTYvMTkyICsgZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMyID0gYygzMi8xOTIgLSBlcHMsIDMyLzE5MiArIGVwcyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzMyA9IGMoNDgvMTkyIC0gZXBzLCA0OC8xOTIgKyBlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgczQgPSBjKDY0LzE5MiAtIGVwcywgNjQvMTkyICsgZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHM1ID0gYyg4MC8xOTIgLSBlcHMsIDgwLzE5MiArIGVwcyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzNiA9IGMoOTYvMTkyIC0gZXBzLCA5Ni8xOTIgKyBlcHMpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0KIyBjaXNzYV90cmVuZCA8LSByWywxXSArIHJbLDJdDQojIGNpc3NhX2N5Y2xlIDwtIHJbLCAzOjExXSB8PiByb3dTdW1zKCkNCiMgY2lzc2Ffc2Vzb25hbCA8LSByWywgYygxNywgMzMsIDQ5LCA2NSwgODEsIDk3KV0gfD4gcm93U3VtcygpDQojIGNpc3NhX3Jlc2lkdWFscyA8LSBJUF92YWx1ZXNfc2xpY2UgLSAoY2lzc2FfdHJlbmQgKyBjaXNzYV9jeWNsZSArIGNpc3NhX3Nlc29uYWwpDQoNCmNpc3NhX3RyZW5kIDwtIHIkdHJlbmQNCmNpc3NhX2N5Y2xlIDwtIHIkY3ljbGUNCmNpc3NhX3Nlc29uYWwgPC0gUmVkdWNlKCIrIiwgcl9zZXNvbmFsIHw+IHdpdGhpbihybShyZXNpZHVhbHMpKSkNCmNpc3NhX3Jlc2lkdWFscyA8LSBJUF92YWx1ZXNfc2xpY2UgLSAoY2lzc2FfdHJlbmQgKyBjaXNzYV9jeWNsZSArIGNpc3NhX3Nlc29uYWwpDQoNCg0KcGxvdChkYXRlc19zbGljZSwgSVBfdmFsdWVzX3NsaWNlLA0KICAgICB0eXBlPSJsIiwgY29sID0gImJsYWNrIikNCmxpbmVzKGRhdGVzX3NsaWNlLCBjaXNzYV90cmVuZCwNCiAgICAgIHR5cGU9ImwiLCBjb2wgPSAicmVkIikNCg0KcGxvdChkYXRlc19zbGljZSwgY2lzc2FfY3ljbGUsDQogICAgIHR5cGU9ImwiLCBjb2wgPSAicmVkIikNCg0KcGxvdChkYXRlc19zbGljZSwgY2lzc2Ffc2Vzb25hbCwNCiAgICAgdHlwZT0ibCIsIGNvbCA9ICJyZWQiKQ0KDQpwbG90KGRhdGVzX3NsaWNlLCBjaXNzYV9yZXNpZHVhbHMsDQogICAgIHR5cGU9ImwiLCBjb2wgPSAicmVkIikNCg0KcGxvdChkYXRlc19zbGljZSwgSVBfdmFsdWVzX3NsaWNlLA0KICAgICB0eXBlPSJsIiwgY29sID0gImJsYWNrIikNCmxpbmVzKGRhdGVzX3NsaWNlLCBjaXNzYV90cmVuZCtjaXNzYV9jeWNsZStjaXNzYV9zZXNvbmFsLA0KICAgICAgdHlwZT0ibCIsIGNvbCA9ICJyZWQiKQ0KYGBgDQoNCiMjIyMgU1NBIGZvc3NhDQoNCmBgYHtyfQ0KcyA8LSBzc2EoSVBfdmFsdWVzX3NsaWNlLCBMID0gMTkyKQ0KZSA8LSBmb3NzYShzKQ0KIyBlIDwtIGVvc3NhX25ldyhzLCBuZXN0ZWQuZ3JvdXBzID0gbGlzdCgxOjMwKSwgY2x1c3RfdHlwZSA9ICJkaXN0YW5jZSIpDQplcHMgPC0gMS8xOTMNCg0KZ3JvdXBzIDwtIGdyb3VwaW5nLmF1dG8oZSwNCiAgICAgICAgICAgICAgICAgICBmcmVxLmJpbnMgPSBsaXN0KHRyZW5kID0gYygxLzE5MiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjeWNsZSA9IGMoMS85NywgNS85NSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzMSA9IGMoMTYvMTkyIC0gZXBzLCAxNi8xOTIgKyBlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgczIgPSBjKDMyLzE5MiAtIGVwcywgMzIvMTkyICsgZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMzID0gYyg0OC8xOTIgLSBlcHMsIDQ4LzE5MiArIGVwcyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzNCA9IGMoNjQvMTkyIC0gZXBzLCA2NC8xOTIgKyBlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgczUgPSBjKDgwLzE5MiAtIGVwcywgODAvMTkyICsgZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHM2ID0gYyg5Ni8xOTIgLSBlcHMsIDk2LzE5MiArIGVwcykNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICAgICAgdGhyZXNob2xkID0gMCkNCg0KDQpwbG90KHdjb3IoZSwgZ3JvdXBzID0gMTozMCksIHNjYWxlcyA9IGxpc3QoYXQgPSBjKDEwLCAyMCwgMzApKSwNCiAgICAgbWFpbiA9ICJXLWNvcnJlbGF0aW9uIG1hdHJpeCBTU0EgKGZvc3NhKSIpDQoNCnIgPC0gcmVjb25zdHJ1Y3QoZSwgZ3JvdXBzPWdyb3VwcykNCg0Kc3NhX3RyZW5kX2YgPC0gciR0cmVuZA0Kc3NhX2N5Y2xlX2YgPC0gciRjeWNsZQ0Kc3NhX3Nlc29uYWxfZiA8LSByJHMxICsgciRzMiArIHIkczMgKyByJHM0ICsgciRzNSArIHIkczYNCnNzYV9yZXNpZHVhbHNfZiA8LSBJUF92YWx1ZXNfc2xpY2UgLSAoc3NhX3RyZW5kX2YgKyBzc2FfY3ljbGVfZiArIHNzYV9zZXNvbmFsX2YpDQoNCnBsb3QoZGF0ZXNfc2xpY2UsIElQX3ZhbHVlc19zbGljZSwNCiAgICAgdHlwZT0ibCIsIGNvbCA9ICJibGFjayIpDQpsaW5lcyhkYXRlc19zbGljZSwgc3NhX3RyZW5kX2YsDQogICAgICB0eXBlPSJsIiwgY29sID0gIm1hZ2VudGEiKQ0KDQpwbG90KGRhdGVzX3NsaWNlLCBzc2FfY3ljbGVfZiwgDQogICAgIHR5cGU9ImwiLCBjb2wgPSAibWFnZW50YSIpDQoNCnBsb3QoZGF0ZXNfc2xpY2UsIHNzYV9zZXNvbmFsX2YsIA0KICAgICB0eXBlPSJsIiwgY29sID0gIm1hZ2VudGEiKQ0KDQpwbG90KGRhdGVzX3NsaWNlLCBzc2FfcmVzaWR1YWxzX2YsDQogICAgIHR5cGU9ImwiLCBjb2wgPSAibWFnZW50YSIpDQoNCmBgYA0KDQojIyMjIFNTQSBlb3NzYQ0KDQpgYGB7cn0NCmxpYnJhcnkoUnNzYSkNCnNvdXJjZSgiZW9zc2FfbmV3LnIiKQ0KcyA8LSBzc2EoSVBfdmFsdWVzX3NsaWNlLCBMID0gMTkyKQ0KZSA8LSBlb3NzYV9uZXcocywgbmVzdGVkLmdyb3VwcyA9IGxpc3QoMTozMCksIGNsdXN0X3R5cGUgPSAiZGlzdGFuY2UiKQ0KDQoNCg0KDQpncm91cHMgPC0gZ3JvdXBpbmcuYXV0byhlLA0KICAgICAgICAgICAgICAgICAgIGZyZXEuYmlucyA9IGxpc3QodHJlbmQgPSBjKDEvMTkyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN5Y2xlID0gYygxLzk3LCA1Lzk1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMxID0gYygxNi8xOTIgLSBlcHMsIDE2LzE5MiArIGVwcyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzMiA9IGMoMzIvMTkyIC0gZXBzLCAzMi8xOTIgKyBlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgczMgPSBjKDQ4LzE5MiAtIGVwcywgNDgvMTkyICsgZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHM0ID0gYyg2NC8xOTIgLSBlcHMsIDY0LzE5MiArIGVwcyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzNSA9IGMoODAvMTkyIC0gZXBzLCA4MC8xOTIgKyBlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgczYgPSBjKDk2LzE5MiAtIGVwcywgOTYvMTkyICsgZXBzKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgICAgICAgICB0aHJlc2hvbGQgPSAwKQ0KcGxvdCh3Y29yKGUsIGdyb3VwcyA9IDE6MzApLCBzY2FsZXMgPSBsaXN0KGF0ID0gYygxMCwgMjAsIDMwKSksDQogICAgIG1haW4gPSAiVy1jb3JyZWxhdGlvbiBtYXRyaXggU1NBIChlb3NzYSkiKQ0KDQpyIDwtIHJlY29uc3RydWN0KGUsIGdyb3Vwcz1ncm91cHMpDQoNCnNzYV90cmVuZCA8LSByJHRyZW5kDQpzc2FfY3ljbGUgPC0gciRjeWNsZQ0Kc3NhX3Nlc29uYWwgPC0gciRzMSArIHIkczIgKyByJHMzICsgciRzNCArIHIkczUgKyByJHM2DQpzc2FfcmVzaWR1YWxzIDwtIElQX3ZhbHVlc19zbGljZSAtIChzc2FfdHJlbmQgKyBzc2FfY3ljbGUgKyBzc2Ffc2Vzb25hbCkNCg0KcGxvdChkYXRlc19zbGljZSwgSVBfdmFsdWVzX3NsaWNlLA0KICAgICB0eXBlPSJsIiwgY29sID0gImJsYWNrIikNCmxpbmVzKGRhdGVzX3NsaWNlLCBzc2FfdHJlbmQsDQogICAgICB0eXBlPSJsIiwgY29sID0gImJsdWUiKQ0KDQpwbG90KGRhdGVzX3NsaWNlLCBzc2FfY3ljbGUsIA0KICAgICB0eXBlPSJsIiwgY29sID0gImJsdWUiKQ0KDQpwbG90KGRhdGVzX3NsaWNlLCBzc2Ffc2Vzb25hbCwgDQogICAgIHR5cGU9ImwiLCBjb2wgPSAiYmx1ZSIpDQoNCnBsb3QoZGF0ZXNfc2xpY2UsIHNzYV9yZXNpZHVhbHMsDQogICAgIHR5cGU9ImwiLCBjb2wgPSAiYmx1ZSIpDQpgYGANCg0KYGBge3J9DQpwbG90KGRhdGVzX3NsaWNlLCBJUF92YWx1ZXNfc2xpY2UsDQogICAgIG1haW4gPSAiSVAgVVNBINGC0YDQtdC90LQiLHhsYWIgPSAi0JLRgNC10LzRjyIsIHlsYWIgPSAi0JfQvdCw0YfQtdC90LjQtSIsDQogICAgIHR5cGU9ImwiLCBjb2wgPSAiYmxhY2siKQ0KbGluZXMoZGF0ZXNfc2xpY2UsIHNzYV90cmVuZCwNCiAgICAgIHR5cGU9ImwiLCBjb2wgPSAiYmx1ZSIsIGx3ZD0yKQ0KbGluZXMoZGF0ZXNfc2xpY2UsIHNzYV90cmVuZF9mLA0KICAgICAgdHlwZT0ibCIsIGNvbCA9ICJtYWdlbnRhIiwgbHdkPTIpDQpsaW5lcyhkYXRlc19zbGljZSwgY2lzc2FfdHJlbmQsDQogICAgICB0eXBlPSJsIiwgY29sID0gInJlZCIsIGx3ZD0yKQ0KIyDQm9C10LPQtdC90LTQsA0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kID0gYygi0JLQtdGB0Ywg0YDRj9C0IiwgIkNpU1NBINGC0YDQtdC90LQiLCAiU1NBINGC0YDQtdC90LQgKGVvc3NhKSIsICJTU0Eg0YLRgNC10L3QtCAoZm9zc2EpIiksIA0KICAgICAgIGNvbCA9IGMoImJsYWNrIiwgInJlZCIsICJibHVlIiwgIm1hZ2VudGEiKSwgbHR5ID0gMSwgbHdkID0gMykNCg0KDQpwbG90KGRhdGVzX3NsaWNlLCBzc2FfY3ljbGUsDQogICAgIG1haW4gPSAiSVAgVVNBINGG0LjQutC70LjRh9C90L7RgdGC0YwiLCB4bGFiID0gItCS0YDQtdC80Y8iLCB5bGFiID0gItCX0L3QsNGH0LXQvdC40LUiLA0KICAgICB0eXBlPSJsIiwgY29sID0gImJsdWUiLCB5bGltPWMoLTEwLCAxMCksIGx3ZD0yKQ0KbGluZXMoZGF0ZXNfc2xpY2UsIGNpc3NhX2N5Y2xlLA0KICAgICAgdHlwZT0ibCIsIGNvbCA9ICJyZWQiLCBsd2Q9MikNCmxpbmVzKGRhdGVzX3NsaWNlLCBzc2FfY3ljbGVfZiwNCiAgICAgIHR5cGU9ImwiLCBjb2wgPSAibWFnZW50YSIsIGx3ZD0yKQ0KIyDQm9C10LPQtdC90LTQsA0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kID0gYygiQ2lTU0EiLCAiU1NBIChlb3NzYSkiLCAiU1NBIChmb3NzYSkiKSwgDQogICAgICAgY29sID0gYygicmVkIiwgImJsdWUiLCAibWFnZW50YSIpLCBsdHkgPSAxLCBsd2QgPSAzKQ0KDQpgYGANCg0KYGBge3J9DQojINCd0LDRgdGC0YDQvtC50LrQsCDQs9GA0LDRhNC40LrQvtCyINC00LvRjyDQvtGC0L7QsdGA0LDQttC10L3QuNGPINC00LLRg9GFINCz0YDQsNGE0LjQutC+0LIg0L7QtNC40L0g0L/QvtC0INC00YDRg9Cz0LjQvCDRgSDQvtCx0YnQtdC5INC+0YHRjNGOIFgNCmxheW91dChtYXRyaXgoYygxLCAyKSwgbnJvdyA9IDIsIGJ5cm93ID0gVFJVRSksIGhlaWdodHMgPSBjKDEsIDEuMikpDQoNCiMg0J/QvtGB0YLRgNC+0LXQvdC40LUg0L/QtdGA0LLQvtCz0L4g0LPRgNCw0YTQuNC60LANCnBhcihtYXIgPSBjKDIsIDQsIDIsIDIpKSAjINCj0LzQtdC90YzRiNC10L3QuNC1INC90LjQttC90LXQs9C+INC+0YLRgdGC0YPQv9CwDQpwbG90KGRhdGVzX3NsaWNlLCBzc2Ffc2Vzb25hbCwgdHlwZSA9ICJsIiwgY29sID0gImJsdWUiLCBsd2QgPSAxLA0KICAgICBtYWluID0gIlNTQSAoZW9zc2EpINGB0LXQt9C+0L3QvdC+0YHRgtGMIiwgeGxhYiA9ICIiLCB5bGFiID0gItCX0L3QsNGH0LXQvdC40LUiKQ0KIyDQlNC+0LHQsNCy0LvQtdC90LjQtSDQvtGB0LggWCDQstC90LjQt9GDINC/0LXRgNCy0L7Qs9C+INCz0YDQsNGE0LjQutCwLCDQvdC+INGBINC/0YPRgdGC0YvQvNC4INC80LXRgtC60LDQvNC4DQpheGlzKDEsIGxhYmVscyA9IEZBTFNFKQ0KDQojINCf0L7RgdGC0YDQvtC10L3QuNC1INCy0YLQvtGA0L7Qs9C+INCz0YDQsNGE0LjQutCwDQpwYXIobWFyID0gYyg1LCA0LCAyLCAyKSkgIyDQo9Cy0LXQu9C40YfQtdC90LjQtSDQvdC40LbQvdC10LPQviDQvtGC0YHRgtGD0L/QsA0KcGxvdChkYXRlc19zbGljZSwgc3NhX3Nlc29uYWxfZiwgdHlwZSA9ICJsIiwgY29sID0gIm1hZ2VudGEiLCBsd2QgPSAxLA0KICAgICBtYWluID0gIlNTQSAoZm9zc2EpINGB0LXQt9C+0L3QvdC+0YHRgtGMIiwgeGxhYiA9ICLQktGA0LXQvNGPIiwgeWxhYiA9ICLQl9C90LDRh9C10L3QuNC1IikNCg0KcGFyKG1hciA9IGMoMywgNCwgMiwgMikpICMg0KPQstC10LvQuNGH0LXQvdC40LUg0L3QuNC20L3QtdCz0L4g0L7RgtGB0YLRg9C/0LANCnBsb3QoZGF0ZXNfc2xpY2UsIGNpc3NhX3Nlc29uYWwsIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLCBsd2QgPSAxLA0KICAgICBtYWluID0gIkNpU1NBINGB0LXQt9C+0L3QvdC+0YHRgtGMIiwgeGxhYiA9ICLQktGA0LXQvNGPIiwgeWxhYiA9ICLQl9C90LDRh9C10L3QuNC1IikNCg0KIyDQktC+0YHRgdGC0LDQvdC+0LLQu9C10L3QuNC1INC80LDQutC10YLQsCDQv9C+INGD0LzQvtC70YfQsNC90LjRjg0KbGF5b3V0KDEpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KcGxvdChkYXRlc19zbGljZSwgc3NhX3Jlc2lkdWFscywgDQogICAgIG1haW4gPSAiSVAgVVNBINC+0YHRgtCw0YLQvtC6IiwgeGxhYiA9ICLQktGA0LXQvNGPIiwgeWxhYiA9ICLQl9C90LDRh9C10L3QuNC1IiwNCiAgICAgdHlwZT0ibCIsIGNvbCA9ICJibHVlIiwgeWxpbT1jKC0yLCAyKSkNCmxpbmVzKGRhdGVzX3NsaWNlLCBjaXNzYV9yZXNpZHVhbHMsDQogICAgICB0eXBlPSJsIiwgY29sID0gInJlZCIpDQpsaW5lcyhkYXRlc19zbGljZSwgc3NhX3Jlc2lkdWFsc19mLA0KICAgICAgdHlwZT0ibCIsIGNvbCA9ICJtYWdlbnRhIikNCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZCA9IGMoIkNpU1NBIiwgIlNTQSAoZW9zc2EpIiwgIlNTQSAoZm9zc2EpIiksIA0KICAgICAgIGNvbCA9IGMoInJlZCIsICJibHVlIiwgIm1hZ2VudGEiKSwgbHR5ID0gMSwgbHdkID0gMykNCmBgYA0KDQpgYGB7cn0NCnNzYV9yZXNpZHVhbHMgfD4gZGVuc2l0eSgpIHw+IHBsb3QoKQ0KY2lzc2FfcmVzaWR1YWxzIHw+IGRlbnNpdHkoKSB8PiBwbG90KCkNCmBgYA0KDQojIyDQntGC0LTQtdC70LXQvdC40LUg0YHQuNCz0L3QsNC70LAg0L7RgiDRiNGD0LzQsA0KDQpgYGB7cn0NCnNldC5zZWVkKDEwMCkNCg0Kbl9tc2VfdGVzdHMgPC0gZnVuY3Rpb24obil7DQogIG4gPC0gOTYqMi0xDQogIEwgPC0gOTYNCiAgc2lnbWEgPC0gMC4xDQogIA0KICANCiAgQyA8LSAxDQogIG9tZWdhX2NzIDwtIDEvMTINCiAgb21lZ2Ffc24gPC0gMS8yNA0KICBhIDwtIDEvMTAwDQogIGZfc3VtIDwtIGZ1bmN0aW9uKHgpew0KICAgIGZfY29uc3QoeCwgQyA9IEMpICsNCiAgICAgIGZfY29zKHgsIG9tZWdhID0gb21lZ2FfY3MpICsNCiAgICAgIGZfZXhwKHgsIGEgPSBhKSArDQogICAgICBmX3Npbih4LCBvbWVnYSA9IG9tZWdhX3NuKQ0KICB9DQogIA0KICANCiAgZl9DIDwtIGZfY29uc3QgfD4gZ2VuZXJhdGVfdHMobiwgQyA9IEMpDQogIGZfYyA8LSBmX2NvcyB8PiBnZW5lcmF0ZV90cyhuLCBvbWVnYSA9IG9tZWdhX2NzKQ0KICBmX3MgPC0gZl9zaW4gfD4gZ2VuZXJhdGVfdHMobiwgb21lZ2EgPSBvbWVnYV9zbikNCiAgZl9lIDwtIGZfZXhwIHw+IGdlbmVyYXRlX3RzKG4sIGEgPSBhKQ0KICANCiAgbXNlX2xzdCA8LSBsaXN0KCkNCiAgZm9yIChpIGluIDE6bikgew0KICAgIGZfbm9pc2UgPC0gcm5vcm0obiwgc2QgPSBzaWdtYSkNCiAgICANCiAgICBmX24gPC0gZl9zdW0oMTpuKSArIGZfbm9pc2UNCiAgICANCiAgICANCiAgICANCiAgICBjIDwtIGNpcmN1bGFudF9TU0EoZl9uLCBMID0gTCwgZXh0ZW5kX2ZsYWcgPSBUUlVFKQ0KICAgICMgciA8LSBjJHRfc2VyaWVzDQogICAgciA8LSBncm91cGluZ19jaXNzYShjLCBncm91cHM9IGxpc3QodHJlbmQgPSBjKDAsIDEvMTAwMCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWwyID0gYygxLzI1LCAxLzIzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsMSA9IGMoMS8xMywgMS8xMCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSR0X3Nlcmllcw0KICAgIA0KICAgICMgbXNlX2xzdCRjaXNzYSA8LSBjKG1zZV9sc3QkY2lzc2EsIG1zZShmX3N1bSgxOm4pLCByWywgOV0gKyByWywgNV0gKyByWywgMV0pKSANCiAgICBtc2VfbHN0JGNpc3NhIDwtIGMobXNlX2xzdCRjaXNzYSwNCiAgICAgICAgICAgICAgICAgICAgICAgbXNlKGZfc3VtKDE6biksDQogICAgICAgICAgICAgICAgICAgICAgICAgICByJHRyZW5kICsgciRzZXNvbmFsMSArIHIkc2Vzb25hbDIpKSANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICBzIDwtIHNzYShmX24sIEwpDQogICAgIyBlIDwtIGVvc3NhKHMsIDE6MTAsIGsgPSA2KQ0KICAgIGUgPC0gZm9zc2EocykNCiAgICANCiAgICBnX3Nlc29uYWwgPC0gZ3JvdXBpbmcuYXV0byhlLCBiYXNlID0gImVpZ2VuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgZnJlcS5iaW5zID0gbGlzdCh0cmVuZCA9IDEvMTAwMCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbDIgPSBjKDEvMjUsIDEvMjMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWwxID0gYygxLzEzLCAxLzEwKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICAgICAgICAgIHRocmVzaG9sZCA9IDAuNSkNCiAgICANCiAgICByIDwtIHJlY29uc3RydWN0KGUsIGdyb3Vwcz1jKGxpc3QoZXhwID0gMSwgQyA9IDIpLCBnX3Nlc29uYWwpKQ0KICAgIA0KICAgIG1zZV9sc3Qkc3NhIDwtIA0KICAgICAgYyhtc2VfbHN0JHNzYSwgbXNlKGZfc3VtKDE6biksIHIkdHJlbmQgKyByJHNlc29uYWwyICsgciRzZXNvbmFsMSkpDQogDQogIH0NCiAgcmV0dXJuKG1zZV9sc3QpDQp9DQoNCnJlc19tc2VfdGVzdCA8LSBuX21zZV90ZXN0cygxMDAwMCkNCg0KYGBgDQoNCmBgYHtyfQ0KIyDQntGG0LXQvdC60LAg0L/Qu9C+0YLQvdC+0YHRgtC4DQpkZW5zaXR5X2VzdGltYXRlX2Npc3NhIDwtIGRlbnNpdHkocmVzX21zZV90ZXN0JGNpc3NhKQ0KDQojINCf0L7RgdGC0YDQvtC10L3QuNC1INCz0YDQsNGE0LjQutCwINC/0LvQvtGC0L3QvtGB0YLQuA0KcGxvdChkZW5zaXR5X2VzdGltYXRlX2Npc3NhLCBtYWluID0gItCe0YbQtdC90LrQsCDQv9C70L7RgtC90L7RgdGC0LgiLCANCiAgICAgeGxhYiA9ICLQl9C90LDRh9C10L3QuNC1IiwgeWxhYiA9ICLQn9C70L7RgtC90L7RgdGC0YwiLCANCiAgICAgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KDQpkZW5zaXR5X2VzdGltYXRlX3NzYSA8LSBkZW5zaXR5KHJlc19tc2VfdGVzdCRzc2EpDQoNCiMg0J/QvtGB0YLRgNC+0LXQvdC40LUg0LPRgNCw0YTQuNC60LAg0L/Qu9C+0YLQvdC+0YHRgtC4DQpwbG90KGRlbnNpdHlfZXN0aW1hdGVfc3NhLCBtYWluID0gItCe0YbQtdC90LrQsCDQv9C70L7RgtC90L7RgdGC0LgiLCANCiAgICAgeGxhYiA9ICLQl9C90LDRh9C10L3QuNC1IiwgeWxhYiA9ICLQn9C70L7RgtC90L7RgdGC0YwiLCANCiAgICAgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KDQpyZXNfbXNlX3Rlc3QkY2lzc2EgfD4gc3VtbWFyeSgpDQpyZXNfbXNlX3Rlc3QkY2lzc2EgfD4gc2QoKQ0KcmVzX21zZV90ZXN0JHNzYSB8PiBzdW1tYXJ5KCkNCnJlc19tc2VfdGVzdCRzc2EgfD4gc2QoKQ0KYGBgDQoNCiMjINCa0LDQuiDQstGL0L/QvtC70L3Rj9C10YLRgdGPINGA0LDRgdGI0LjRgNC10L3QuNC1INGA0Y/QtNCwDQoNCmBgYHtyfQ0KSVBfdmFsdWVzX3NsaWNlIHw+IGV4dGVuZCgxOTIpIHw+IHBsb3QodHlwZT0ibCIsIGx3ZCA9IDMpDQpjKHJlcCgwLCAxOTIpLElQX3ZhbHVlc19zbGljZSkgfD4gbGluZXModHlwZT0ibCIsIGNvbD0icmVkIikNCg0KYGBgDQoNClx8DQoNCmBgYHtyfQ0KbiA8LSA5NioyICsgNg0KeCA8LSAwOihuLTEpDQp5IDwtIHNpbigyKnBpLzEyICogeCkNCkwgPC0gOTYrNg0KeSB8PiBleHRlbmQoTCkgfD4gcGxvdCh0eXBlPSJsIiwgbHdkID0gMykNCmMocmVwKDAsIEwpLCB5KSB8PiBsaW5lcyh0eXBlPSJsIiwgY29sPSJyZWQiLCBsd2QgPSAzKQ0KDQpgYGANCg0KIyMgQ2lTU0Eg0YfQtdGA0LXQtyDQpNGD0YDRjNC1DQoNCiMjIyBJUF92YWx1ZXMNCg0KYGBge3J9DQpjaXNzYV9saWtlX2ZvdXJpZXJfdHJhbnNmb3JtIDwtIGZ1bmN0aW9uKHRzLCBMKXsNCiAgcmVjb25zdHJ1Y3RfZmZ0IDwtIGZ1bmN0aW9uKHgsIHksIGZyZXF1ZW5jaWVzKSB7DQogICAgZmZ0X3kgPC0gZmZ0KHkpDQogIA0KICAgIGFtcGxpdHVkZXMgPC0gTW9kKGZmdF95KQ0KICAgIHBoYXNlcyA8LSBBcmcoZmZ0X3kpDQogICAgDQogICAgcmVjb25zdHJ1Y3RlZCA8LSBtYXRyaXgoMCwgbGVuZ3RoKGFtcGxpdHVkZXMpLCBsZW5ndGgoeCkpDQogICAgbiA8LSBsZW5ndGgoYW1wbGl0dWRlcykNCiAgICBmb3IgKGkgaW4gMToobGVuZ3RoKGFtcGxpdHVkZXMpKSkgew0KICAgICAgcmVjb25zdHJ1Y3RlZFtpLCBdIDwtDQogICAgICAgIGFtcGxpdHVkZXNbaV0gKiANCiAgICAgICAgY29zKDIgKiBwaSAqIGZyZXF1ZW5jaWVzW2ldICogKHgpICsgcGhhc2VzW2ldKSAvDQogICAgICAgIG4NCiAgICB9DQogICAgcmV0dXJuKGxpc3QoDQogICAgICB0cyA9IHJlY29uc3RydWN0ZWQsDQogICAgICBmcmVxdWVuY2llcyA9IGZyZXF1ZW5jaWVzDQogICAgICApKQ0KICB9DQogIA0KICBuIDwtIGxlbmd0aCh0cykNCiAgeCA8LSAwOihuLTEpDQogIEwgPC0gTA0KICBmcmVxdWVuY2llcyA8LSAoMDooTC0xKSkgLyBMDQogIHkgPC0gdHMNCiAgeV9tYWluIDwtIHkNCiAgeF9tYWluIDwtIHgNCiAgDQogIFggPC0gaGFua2VsKHksIEwpDQogIEsgPC0gZGltKFgpWzJdDQogIHJlcyA8LSBsaXN0KCkNCiAgZm9yIChpIGluIDE6Syl7DQogICAgeSA8LSBYWywgaV0NCiAgICB4IDwtIHhfbWFpblsxOigxICsgTCAtIDEpXQ0KICAgIHJlc1tbaV1dIDwtIHJlY29uc3RydWN0X2ZmdCh4LCB5LCBmcmVxdWVuY2llcykkdHMNCiAgfQ0KICANCiAgIyBmb3IgKGkgaW4gMTpMKXsNCiAgIyAgIHBsb3QoeCwgcmVzW1tpXV1bOSwgXSkNCiAgIyB9DQogIA0KICByZXNfbXVsdCA8LSByZXMNCiAgIyByZXMNCiAgDQogIGF2ZXJhZ2luZyA8LSBmdW5jdGlvbihyZXNfY29tcF93aXNlX211bHQpew0KICAgIEsgPC0gZGltKFgpWzJdDQogICAgY291bnRlcnMgPC0gcmVwKDAsIG4pDQogICAgcmVzIDwtIG1hdHJpeCgwLCBuY29sID0gbiwgbnJvdyA9IEwpDQogICAgZm9yIChpIGluIDE6bGVuZ3RoKHJlc19jb21wX3dpc2VfbXVsdCkpew0KICAgICAgcmVzWywgaTooaStMLTEpXSA8LSByZXNbLCBpOihpK0wtMSldICsgcmVzX2NvbXBfd2lzZV9tdWx0W1tpXV0NCiAgICAgIGNvdW50ZXJzW2k6KGkrTC0xKV0gPC0gY291bnRlcnNbaTooaStMLTEpXSArIDENCiAgICB9DQogICAgZm9yIChpIGluIDE6bil7DQogICAgICByZXNbLCBpXSA8LSByZXNbLCBpXSAvIGNvdW50ZXJzW2ldDQogICAgfQ0KICAgIHJlcw0KICB9DQogIA0KICBhdnIgPC0gYXZlcmFnaW5nKHJlc19tdWx0KQ0KICANCiAgZ3JvdXBfYnlfZWxlbWVudGFyeV9mcmVxX2ZvdXJlaXIgPC0gZnVuY3Rpb24ocmVzX2F2ZXJhZ2VkKXsNCiAgICBuZjIgPC0gMA0KICAgIGlmIChMICUlIDIpIHsNCiAgICAgIG5mMiA8LSAoTCArIDEpIC8gMiAtIDENCiAgICB9IGVsc2Ugew0KICAgICAgbmYyIDwtIEwgLyAyIC0gMQ0KICAgIH0NCiAgICBuZnQgPC0gbmYyICsgYWJzKChMICUlIDIpIC0gMikNCiAgICANCiAgICBaIDwtIG1hdHJpeCgwLCBuY29sID0gbmZ0LCBucm93ID0gbikNCiAgICANCiAgICAjIHByaW50KFogfD4gZGltKCkpDQogICAgIyBwcmludChyZXNfYXZlcmFnZWQgfD4gZGltKCkpDQogICAgDQogICAgWlssIDFdIDwtIHJlc19hdmVyYWdlZFsxLCBdDQogICAgZm9yIChrIGluIDE6bmYyKSB7DQogICAgICBaWywgayArIDFdIDwtIHJlc19hdmVyYWdlZFtrICsgMSwgXSArIHJlc19hdmVyYWdlZFtMICsgMiAtIChrICsgMSksIF0NCiAgICB9DQogICAgaWYgKEwgJSUgMiAhPSAwKSB7DQogICAgICBaWywgbmZ0XSA8LSByZXNfYXZlcmFnZWRbbmZ0LCBdDQogICAgfQ0KICAgIA0KICAgIA0KICAgIHJldHVybihsaXN0KA0KICAgICAgdF9zZXJpZXMgPSBaLA0KICAgICAgZnJlcSA9ICgwOmRpbShaKVsyXSkvTA0KICAgICkpDQogIH0NCg0KDQogIHJzIDwtIGdyb3VwX2J5X2VsZW1lbnRhcnlfZnJlcV9mb3VyZWlyKGF2cikNCiAgcmV0dXJuKHJzKQ0KfQ0KDQpgYGANCg0KYGBge3J9DQpkYXRhX3NsaWNlIDwtIDE6NTM3DQpkYXRlc19zbGljZSA8LSBkYXRlc1tkYXRhX3NsaWNlXQ0KSVBfdmFsdWVzX3NsaWNlIDwtIElQX3ZhbHVlc1tkYXRhX3NsaWNlXQ0KZXBzIDwtIDEvMTkzDQoNCg0KYyA8LSBjaXJjdWxhbnRfU1NBKElQX3ZhbHVlc19zbGljZSwgTCA9IDE5MiwgZXh0ZW5kX2ZsYWcgPSBGQUxTRSkNCnIgPC0gYyR0X3Nlcmllcw0KDQpjX2Z0IDwtIGNpc3NhX2xpa2VfZm91cmllcl90cmFuc2Zvcm0oSVBfdmFsdWVzX3NsaWNlLCBMID0gMTkyKQ0Kcl9mdCA8LSBjX2Z0JHRfc2VyaWVzDQoNCmZvciAoaSBpbiAxOmRpbShyKVsyXSl7DQogIHBsb3QoZGF0YV9zbGljZSwgcl9mdFssIGldLCBjb2w9ICJyZWQiLCB0eXBlID0gImwiLCBsd2QgPSAyKQ0KICBsaW5lcyhkYXRhX3NsaWNlLCByWywgaV0pDQp9DQpgYGANCg0KIyMjINCh0YDQsNCy0L3QtdC90LjQtSDRgNCw0LfQu9C+0LbQtdC90LjQuSDQstGB0LXQs9C+INCy0YDQtdC80LXQvdC90L7Qs9C+INGA0Y/QtNCwINGH0LXRgNC10Lcg0LzQtdGC0L7QtCDQpNGD0YDRjNC1LCBTU0EsIGF1dG9fU1NBLCBDaVNTQSDQuCBDaVNTQSDRgSDRgNCw0YHRiNC40YDQtdC90LjQtdC8INGA0Y/QtNCwDQoNCmBgYHtyfQ0KcmVjb25zdHJ1Y3RfZmZ0IDwtIGZ1bmN0aW9uKHhfaW5pdCwgeV9pbml0LCBleHRlbmRfZmxhZyA9IEZBTFNFKSB7DQogICAgeCA8LSB4X2luaXQNCiAgICB5IDwtIHlfaW5pdA0KICAgIE4gPC0gbGVuZ3RoKHlfaW5pdCkNCiAgICBIIDwtIDANCiAgICBpZiAoZXh0ZW5kX2ZsYWcgPT0gVFJVRSl7DQogICAgICBIIDwtIGxlbmd0aCh5KSAlLyUgMg0KICAgICAgeSA8LSBleHRlbmQoeSwgSCkNCiAgICAgIHggPC0gMDoobGVuZ3RoKHkpIC0gMSkNCiAgICB9DQogICAgDQogICAgZnJlcXVlbmNpZXMgPC0gKDA6KGxlbmd0aCh4KS0xKSkgLyBsZW5ndGgoeCkNCiAgICBmZnRfeSA8LSBmZnQoeSkNCiAgICANCiAgICBhbXBsaXR1ZGVzIDwtIE1vZChmZnRfeSkNCiAgICBwaGFzZXMgPC0gQXJnKGZmdF95KQ0KICAgIA0KICAgIHJlY29uc3RydWN0ZWQgPC0gbWF0cml4KDAsIGxlbmd0aChhbXBsaXR1ZGVzKSwgbGVuZ3RoKHgpKQ0KICAgIG4gPC0gbGVuZ3RoKGFtcGxpdHVkZXMpDQogICAgTCA8LSBuDQogICAgZm9yIChpIGluIDE6KGxlbmd0aChhbXBsaXR1ZGVzKSkpIHsNCiAgICAgIHJlY29uc3RydWN0ZWRbaSwgXSA8LQ0KICAgICAgICBhbXBsaXR1ZGVzW2ldICogDQogICAgICAgIGNvcygyICogcGkgKiBmcmVxdWVuY2llc1tpXSAqICh4KSArIHBoYXNlc1tpXSkgLw0KICAgICAgICBuDQogICAgfQ0KICAgIA0KICAgIA0KICAgIA0KICANCiAgICBncm91cF9ieV9lbGVtZW50YXJ5X2ZyZXFfZm91cmVpciA8LSBmdW5jdGlvbihyZXNfYXZlcmFnZWQpew0KICAgICAgbmYyIDwtIDANCiAgICAgIGlmIChMICUlIDIpIHsNCiAgICAgICAgbmYyIDwtIChMICsgMSkgLyAyIC0gMQ0KICAgICAgfSBlbHNlIHsNCiAgICAgICAgbmYyIDwtIEwgLyAyIC0gMQ0KICAgICAgfQ0KICAgICAgbmZ0IDwtIG5mMiArIGFicygoTCAlJSAyKSAtIDIpDQogICAgICANCiAgICAgIFogPC0gbWF0cml4KDAsIG5jb2wgPSBuZnQsIG5yb3cgPSBuKQ0KICAgICAgDQogICAgICAjIHByaW50KFogfD4gZGltKCkpDQogICAgICAjIHByaW50KHJlc19hdmVyYWdlZCB8PiBkaW0oKSkNCiAgICAgIA0KICAgICAgWlssIDFdIDwtIHJlc19hdmVyYWdlZFsxLCBdDQogICAgICBmb3IgKGsgaW4gMTpuZjIpIHsNCiAgICAgICAgWlssIGsgKyAxXSA8LSByZXNfYXZlcmFnZWRbayArIDEsIF0gKyByZXNfYXZlcmFnZWRbTCArIDIgLSAoayArIDEpLCBdDQogICAgICB9DQogICAgICBpZiAoTCAlJSAyICE9IDApIHsNCiAgICAgICAgWlssIG5mdF0gPC0gcmVzX2F2ZXJhZ2VkW25mdCwgXQ0KICAgICAgfQ0KICAgICAgDQogICAgICANCiAgICAgIHJldHVybihsaXN0KA0KICAgICAgICB0X3NlcmllcyA9IFpbKEgrMSk6KE4rSCksIF0sDQogICAgICAgIGZyZXEgPSAoMDooZGltKFopWzJdLTEpKS9MDQogICAgICApKQ0KICAgIH0NCiAgDQogIA0KICAgIHJzIDwtIGdyb3VwX2J5X2VsZW1lbnRhcnlfZnJlcV9mb3VyZWlyKHJlY29uc3RydWN0ZWQpDQogICAgDQogICAgDQogICAgcmV0dXJuKGxpc3QoDQogICAgICB0X3NlcmllcyA9IHJzJHRfc2VyaWVzLA0KICAgICAgZnJlcSA9IHJzJGZyZXENCiAgICAgICkpDQogIH0NCmBgYA0KDQojIyMjINCY0LTQtdCw0LvRjNC90YvQuSDRgdC70YPRh9Cw0Lkg0LTQu9GPIENpU1NBINC4IEZvdXJpZXINCg0KYGBge3J9DQpuIDwtIDk2KjINCkwgPC0gOTYNCnggPC0gMDoobi0xKQ0KeTEgPC0gc2luKDIqcGkvMTIgKiB4KQ0KeTIgPC0gY29zKDIqcGkvMyAqIHgpLzINCnkgPC0geTEgKyB5Mg0KWCA8LSBoYW5rZWwoeSwgTCA9IEwpDQplcHMgPC0gMS8obisxKQ0KDQpzX3NzYSA8LSBzc2EoeVsxOihuLTEpXSwgTCkNCnJfc3NhIDwtIHJlY29uc3RydWN0KHNfc3NhLCBncm91cHMgPSBsaXN0KA0KICBGMSA9IGMoMSwgMiksDQogIEYyID0gYygzLCA0KQ0KKSkNCiMgcl9zc2EgPC0gcmVjb25zdHJ1Y3Qoc19zc2EsIGdyb3Vwcz1saXN0KA0KIyAgIHNlc29uYWxfc2luID0gYygxLCAyKSwNCiMgICBzZXNvbmFsX2NvcyA9IGMoMywgNCkNCiMgKSkNCiMgcGxvdCh4LCByX3NzYSRGMSwgdHlwZT0ibCIpDQojIHBsb3QoeCwgcl9zc2EkRjIsIHR5cGU9ICJsIikNCiMgcGxvdCh3Y29yKHNfc3NhLCBncm91cHMgPSAxOjEwKSwgc2NhbGVzID0gbGlzdChhdCA9IGMoMTAsIDIwLCAzMCkpKQ0KZV9zc2EgPC0gZW9zc2FfbmV3KHNfc3NhLCBuZXN0ZWQuZ3JvdXBzID0gbGlzdCgxOjQpLCBjbHVzdF90eXBlID0gImRpc3RhbmNlIikNCmdfc2Vzb25hbF9lIDwtIGdyb3VwaW5nLmF1dG8oZV9zc2EsIGJhc2UgPSAiZWlnZW4iLA0KICAgICAgICAgICAgICAgICAgICAgICBmcmVxLmJpbnMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfc2luID0gYygxLzEyLWVwcywgMS8xMitlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfY29zID0gYygxLzMtZXBzLCAxLzMrZXBzKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICAgICAgICAgIHRocmVzaG9sZCA9IDAuNSkNCnJfc3NhX2UgPC0gcmVjb25zdHJ1Y3QoZV9zc2EsIGdyb3Vwcz1nX3Nlc29uYWxfZSkNCiMgcGxvdCh4LCByX3NzYV9lJHNlc29uYWxfc2luKQ0KIyBwbG90KHgsIHJfc3NhX2Ukc2Vzb25hbF9jb3MpDQoNCg0KDQpyX2ZmdCA8LSByZWNvbnN0cnVjdF9mZnQoeCwgeSkNCnJfZmZ0X2dyb3VwZWQgPC0gZ3JvdXBpbmdfY2lzc2Eocl9mZnQsDQogICAgICAgICAgICAgICAgICAgIGdyb3VwcyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMy1lcHMsIDEvMytlcHMpDQogICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0KDQpyX2ZmdF9leHRlbmRlZCA8LSByZWNvbnN0cnVjdF9mZnQoeCwgeSwgVFJVRSkNCnJfZmZ0X2dyb3VwZWRfZXh0ZW5kZWQgPC0gZ3JvdXBpbmdfY2lzc2Eocl9mZnRfZXh0ZW5kZWQsDQogICAgICAgICAgICAgICAgICAgIGdyb3VwcyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMy1lcHMsIDEvMytlcHMpDQogICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0KDQojIHJfZmZ0X2dyb3VwZWQkc2Vzb25hbF9zaW4gfD4gbGVuZ3RoKCkNCg0KIyBwbG90KHgsIHJfZmZ0X2dyb3VwZWQkc2Vzb25hbF9zaW4pDQojIHBsb3QoeCwgcl9mZnRfZ3JvdXBlZCRzZXNvbmFsX2NvcykNCiMgcGxvdCh4LCByX2ZmdF9ncm91cGVkJHJlc2lkdWFscykNCg0KDQpyX2Npc3NhIDwtIGNpcmN1bGFudF9TU0EoeSwgTCkNCnJfY2lzc2FfZ3JvdXBlZCA8LSBncm91cGluZ19jaXNzYShyX2Npc3NhLA0KICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfc2luID0gYygxLzEyLWVwcywgMS8xMitlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfY29zID0gYygxLzMtZXBzLCAxLzMrZXBzKQ0KICAgICAgICAgICAgICAgICAgICApDQogICAgICAgICAgICAgICAgICAgICkkdF9zZXJpZXMNCg0KDQpyX2Npc3NhX2V4dCA8LSBjaXJjdWxhbnRfU1NBKHksIEwsIGV4dGVuZF9mbGFnID0gVFJVRSkNCnJfY2lzc2FfZ3JvdXBlZF9leHQgPC0gZ3JvdXBpbmdfY2lzc2Eocl9jaXNzYV9leHQsDQogICAgICAgICAgICAgICAgICAgIGdyb3VwcyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMy1lcHMsIDEvMytlcHMpDQogICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0KDQojIHBsb3QoeCwgcl9jaXNzYV9ncm91cGVkJHNlc29uYWxfc2luKQ0KIyBwbG90KHgsIHJfY2lzc2FfZ3JvdXBlZCRzZXNvbmFsX2NvcykNCiMgcGxvdCh4LCByX2Npc3NhX2dyb3VwZWQkcmVzaWR1YWxzKQ0KDQpsaWJyYXJ5KHh0YWJsZSkNCg0KIyDQqNCw0LMgMjog0KHQvtC30LTQsNC90LjQtSDQv9GA0LjQvNC10YDQsCDQtNCw0L3QvdGL0YUNCmRhdGEgPC0gZGF0YS5mcmFtZSgNCiAg0JzQtdGC0L7QtCA9IGMoIlNTQSIsICJTU0EgRU9TU0EiLCJGb3VyaWVyIiwgIkNpU1NBIiwgIkNpU1NBIGV4dGVuZGVkIiwgIkZvdXJpZXIgZXh0ZW5kZWQiKSwNCiAgc2luX2VyciA9IGMgKDEsIDIwLCAyMCwgMSwgMSwgMSksDQogIGNvc19lcnIgPSBjKDEsIDEsIDEsIDEsIDEsIDEpDQopDQoNCmRhdGEkc2luX2VyclsxXSA8LSBtc2UoeTFbMToobi0xKV0sIHJfc3NhJEYxKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkgDQpkYXRhJGNvc19lcnJbMV0gPC0gbXNlKHkyWzE6KG4tMSldLCByX3NzYSRGMikgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQoNCmRhdGEkY29zX2VyclsyXSA8LSBtc2UoeTFbMToobi0xKV0sIHJfc3NhX2Ukc2Vzb25hbF9zaW4pIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRzaW5fZXJyWzJdIDwtIG1zZSh5MlsxOihuLTEpXSwgcl9zc2FfZSRzZXNvbmFsX2NvcykgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQoNCg0KZGF0YSRjb3NfZXJyWzNdIDwtIG1zZSh5MSwgcl9mZnRfZ3JvdXBlZCRzZXNvbmFsX3NpbikgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJHNpbl9lcnJbM10gPC0gbXNlKHkyLCByX2ZmdF9ncm91cGVkJHNlc29uYWxfY29zKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCg0KDQpkYXRhJGNvc19lcnJbNF0gPC0gbXNlKHkxLCByX2Npc3NhX2dyb3VwZWQkc2Vzb25hbF9zaW4pIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2Vycls0XSA8LSBtc2UoeTIsIHJfY2lzc2FfZ3JvdXBlZCRzZXNvbmFsX2NvcykgfD4gDQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KDQoNCmRhdGEkY29zX2Vycls1XSA8LSBtc2UoeTEsIHJfY2lzc2FfZ3JvdXBlZF9leHQkc2Vzb25hbF9zaW4pIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2Vycls1XSA8LSBtc2UoeTIsIHJfY2lzc2FfZ3JvdXBlZF9leHQkc2Vzb25hbF9jb3MpIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCg0KZGF0YSRjb3NfZXJyWzZdIDwtIG1zZSh5MSwgcl9mZnRfZ3JvdXBlZF9leHRlbmRlZCRzZXNvbmFsX3NpbikgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJHNpbl9lcnJbNl0gPC0gbXNlKHkyLCByX2ZmdF9ncm91cGVkX2V4dGVuZGVkJHNlc29uYWxfY29zKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCg0KDQoNCnRhYmxlX2xhdGV4IDwtIHh0YWJsZShkYXRhLCBjYXB0aW9uID0gIkV4YW1wbGUgVGFibGUiKQ0KDQojINCo0LDQsyA0OiDQktGL0LLQvtC0INGC0LDQsdC70LjRhtGLINCyIExhVGVYINGE0LDQudC7DQpwcmludCh0YWJsZV9sYXRleCwgaW5jbHVkZS5yb3duYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCiMjIyMg0JjQtNC10LDQu9GM0L3Ri9C5INGB0LvRg9GH0LDQuSDRgSDRiNGD0LzQvtC8DQoNCmBgYHtyfQ0KDQpkYXRhIDwtIGxpc3QoDQogINCc0LXRgtC+0LQgPSBjKCJTU0EiLCJTU0EgRU9TU0EiLCJGb3VyaWVyIiwgIkNpU1NBIiwgIkNpU1NBIGV4dGVuZGVkIiwgIkZvdXJpZXIgZXh0ZW5kZWQiKSwNCiAgc2luX2VyciA9IGxpc3QobGlzdCgpLCBsaXN0KCksIGxpc3QoKSwgbGlzdCgpLCBsaXN0KCksIGxpc3QoKSksDQogIGNvc19lcnIgPSBsaXN0KGxpc3QoKSwgbGlzdCgpLCBsaXN0KCksIGxpc3QoKSwgbGlzdCgpLCBsaXN0KCkpDQopDQoNCmZvciAoaSBpbiAxOjUwKXsNCiAgc2V0LnNlZWQoaSkNCiAgDQogIG4gPC0gOTYqMg0KICBMIDwtIDk2DQogIHggPC0gMDoobi0xKQ0KICB5MSA8LSBzaW4oMipwaS8xMiAqIHgpDQogIHkyIDwtIGNvcygyKnBpLzMgKiB4KS8yDQogIHkgPC0geTEgKyB5MiArIHJub3JtKG4sIDAsIDAuMSkNCiAgWCA8LSBoYW5rZWwoeSwgTCA9IEwpDQogIGVwcyA8LSAxLyhuKzEpDQogIA0KICBzX3NzYSA8LSBzc2EoeVsxOihuLTEpXSwgTCkNCiAgcl9zc2EgPC0gcmVjb25zdHJ1Y3Qoc19zc2EsIGdyb3VwcyA9IGxpc3QoDQogICAgRjEgPSBjKDEsIDIpLA0KICAgIEYyID0gYygzLCA0KQ0KICApKQ0KICAjIHJfc3NhIDwtIHJlY29uc3RydWN0KHNfc3NhLCBncm91cHM9bGlzdCgNCiAgIyAgIHNlc29uYWxfc2luID0gYygxLCAyKSwNCiAgIyAgIHNlc29uYWxfY29zID0gYygzLCA0KQ0KICAjICkpDQogICMgcGxvdCh4WzE6KG4tMSldLCByX3NzYSRGMSwgdHlwZSA9ICJsIikNCiAgIyBwbG90KHhbMToobi0xKV0sIHJfc3NhJEYyLCB0eXBlID0gImwiKQ0KICAjIHBsb3Qod2NvcihzX3NzYSwgZ3JvdXBzID0gMToxMCksIHNjYWxlcyA9IGxpc3QoYXQgPSBjKDEwLCAyMCwgMzApKSkNCiAgZV9zc2EgPC0gZW9zc2FfbmV3KHNfc3NhLCBuZXN0ZWQuZ3JvdXBzID0gbGlzdCgxOjQpLCBjbHVzdF90eXBlID0gImRpc3RhbmNlIikNCiAgZ19zZXNvbmFsX2UgPC0gZ3JvdXBpbmcuYXV0byhlX3NzYSwgYmFzZSA9ICJlaWdlbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgZnJlcS5iaW5zID0gbGlzdCgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfc2luID0gYygxLzEyLWVwcywgMS8xMitlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMy1lcHMsIDEvMytlcHMpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHRocmVzaG9sZCA9IDAuNSkNCiAgcl9zc2FfZSA8LSByZWNvbnN0cnVjdChlX3NzYSwgZ3JvdXBzPWdfc2Vzb25hbF9lKQ0KICAjIHBsb3QoeCwgcl9zc2FfZSRzZXNvbmFsX3NpbikNCiAgIyBwbG90KHgsIHJfc3NhX2Ukc2Vzb25hbF9jb3MpDQogIA0KICANCiAgDQogIHJfZmZ0IDwtIHJlY29uc3RydWN0X2ZmdCh4LCB5KQ0KICByX2ZmdF9ncm91cGVkIDwtIGdyb3VwaW5nX2Npc3NhKHJfZmZ0LA0KICAgICAgICAgICAgICAgICAgICAgIGdyb3VwcyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsX3NpbiA9IGMoMS8xMi1lcHMsIDEvMTIrZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfY29zID0gYygxLzMtZXBzLCAxLzMrZXBzKQ0KICAgICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICAgICAgICApJHRfc2VyaWVzDQogIA0KICByX2ZmdF9leHRlbmRlZCA8LSByZWNvbnN0cnVjdF9mZnQoeCwgeSwgVFJVRSkNCiAgcl9mZnRfZ3JvdXBlZF9leHRlbmRlZCA8LSBncm91cGluZ19jaXNzYShyX2ZmdF9leHRlbmRlZCwNCiAgICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsX2NvcyA9IGMoMS8zLWVwcywgMS8zK2VwcykNCiAgICAgICAgICAgICAgICAgICAgICApDQogICAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0KICANCiAgIyByX2ZmdF9ncm91cGVkJHNlc29uYWxfc2luIHw+IGxlbmd0aCgpDQogIA0KICAjIHBsb3QoeCwgcl9mZnRfZ3JvdXBlZCRzZXNvbmFsX3NpbikNCiAgIyBwbG90KHgsIHJfZmZ0X2dyb3VwZWQkc2Vzb25hbF9jb3MpDQogICMgcGxvdCh4LCByX2ZmdF9ncm91cGVkJHJlc2lkdWFscykNCiAgDQogIA0KICByX2Npc3NhIDwtIGNpcmN1bGFudF9TU0EoeSwgTCkNCiAgcl9jaXNzYV9ncm91cGVkIDwtIGdyb3VwaW5nX2Npc3NhKHJfY2lzc2EsDQogICAgICAgICAgICAgICAgICAgICAgZ3JvdXBzID0gbGlzdCgNCiAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfc2luID0gYygxLzEyLWVwcywgMS8xMitlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMy1lcHMsIDEvMytlcHMpDQogICAgICAgICAgICAgICAgICAgICAgKQ0KICAgICAgICAgICAgICAgICAgICAgICkkdF9zZXJpZXMNCiAgDQogIA0KICByX2Npc3NhX2V4dCA8LSBjaXJjdWxhbnRfU1NBKHksIEwsIGV4dGVuZF9mbGFnID0gVFJVRSkNCiAgcl9jaXNzYV9ncm91cGVkX2V4dCA8LSBncm91cGluZ19jaXNzYShyX2Npc3NhX2V4dCwNCiAgICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsX2NvcyA9IGMoMS8zLWVwcywgMS8zK2VwcykNCiAgICAgICAgICAgICAgICAgICAgICApDQogICAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0KICBkYXRhJGNvc19lcnJbWzFdXVtbaV1dIDwtIA0KICAgIG1pbihtc2UoeTFbMToobi0xKV0sIHJfc3NhJEYxKSwgbXNlKHkxWzE6KG4tMSldLCByX3NzYSRGMikpDQogIGRhdGEkc2luX2VycltbMV1dW1tpXV0gPC0NCiAgICBtaW4obXNlKHkyWzE6KG4tMSldLCByX3NzYSRGMSksIG1zZSh5MlsxOihuLTEpXSwgcl9zc2EkRjIpKQ0KICANCiAgZGF0YSRjb3NfZXJyW1syXV1bW2ldXSA8LSBtc2UoeTFbMToobi0xKV0sIHJfc3NhX2Ukc2Vzb25hbF9zaW4pDQogIGRhdGEkc2luX2VycltbMl1dW1tpXV0gPC0gbXNlKHkyWzE6KG4tMSldLCByX3NzYV9lJHNlc29uYWxfY29zKQ0KICANCiAgDQogIGRhdGEkY29zX2VycltbM11dW1tpXV0gPC0gbXNlKHkxLCByX2ZmdF9ncm91cGVkJHNlc29uYWxfc2luKQ0KICBkYXRhJHNpbl9lcnJbWzNdXVtbaV1dIDwtIG1zZSh5Miwgcl9mZnRfZ3JvdXBlZCRzZXNvbmFsX2NvcykNCiAgDQogIA0KICBkYXRhJGNvc19lcnJbWzRdXVtbaV1dIDwtIG1zZSh5MSwgcl9jaXNzYV9ncm91cGVkJHNlc29uYWxfc2luKQ0KICBkYXRhJHNpbl9lcnJbWzRdXVtbaV1dIDwtIG1zZSh5Miwgcl9jaXNzYV9ncm91cGVkJHNlc29uYWxfY29zKQ0KICANCiAgDQogIGRhdGEkY29zX2VycltbNV1dW1tpXV0gPC0gbXNlKHkxLCByX2Npc3NhX2dyb3VwZWRfZXh0JHNlc29uYWxfc2luKQ0KICBkYXRhJHNpbl9lcnJbWzVdXVtbaV1dIDwtIG1zZSh5Miwgcl9jaXNzYV9ncm91cGVkX2V4dCRzZXNvbmFsX2NvcykNCiAgDQogIGRhdGEkY29zX2VycltbNl1dW1tpXV0gPC0gbXNlKHkxLCByX2ZmdF9ncm91cGVkX2V4dGVuZGVkJHNlc29uYWxfc2luKQ0KICBkYXRhJHNpbl9lcnJbWzZdXVtbaV1dIDwtIG1zZSh5Miwgcl9mZnRfZ3JvdXBlZF9leHRlbmRlZCRzZXNvbmFsX2NvcykNCn0NCmxpYnJhcnkoeHRhYmxlKQ0KDQojINCo0LDQsyAyOiDQodC+0LfQtNCw0L3QuNC1INC/0YDQuNC80LXRgNCwINC00LDQvdC90YvRhQ0KZGF0YV9wcmV2IDwtIGRhdGENCg0KZGF0YSA8LSBkYXRhLmZyYW1lKA0KICDQnNC10YLQvtC0ID0gYygiU1NBIiwgIlNTQSBFT1NTQSIsIkZvdXJpZXIiLCAiQ2lTU0EiLCAiQ2lTU0EgZXh0ZW5kZWQiLCAiRm91cmllciBleHRlbmRlZCIpLA0KICBzaW5fZXJyID0gYygwLCAwLCAwLCAwLCAwLCAwKSwNCiAgY29zX2VyciA9IGMoMCwgMCwgMCwgMCwgMCwgMCkNCikNCg0KZGF0YSRjb3NfZXJyWzFdIDwtIG1lYW4oZGF0YV9wcmV2JGNvc19lcnJbWzFdXSB8PiB1bmxpc3QoKSkgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJHNpbl9lcnJbMV0gPC0gbWVhbihkYXRhX3ByZXYkc2luX2VycltbMV1dfD4gdW5saXN0KCkpIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KDQpkYXRhJGNvc19lcnJbMl0gPC0gbWVhbihkYXRhX3ByZXYkY29zX2VycltbMl1dIHw+IHVubGlzdCgpKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2VyclsyXSA8LSBtZWFuKGRhdGFfcHJldiRzaW5fZXJyW1syXV18PiB1bmxpc3QoKSkgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQoNCg0KZGF0YSRjb3NfZXJyWzNdIDwtIG1lYW4oZGF0YV9wcmV2JGNvc19lcnJbWzNdXXw+IHVubGlzdCgpKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2VyclszXSA8LSBtZWFuKGRhdGFfcHJldiRzaW5fZXJyW1szXV18PiB1bmxpc3QoKSkgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQoNCg0KZGF0YSRjb3NfZXJyWzRdIDwtIG1lYW4oZGF0YV9wcmV2JGNvc19lcnJbWzRdXXw+IHVubGlzdCgpKSB8PiANCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJHNpbl9lcnJbNF0gPC0gbWVhbihkYXRhX3ByZXYkc2luX2VycltbNF1dfD4gdW5saXN0KCkpIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCg0KDQpkYXRhJGNvc19lcnJbNV0gPC0gbWVhbihkYXRhX3ByZXYkY29zX2VycltbNV1dfD4gdW5saXN0KCkpIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2Vycls1XSA8LSBtZWFuKGRhdGFfcHJldiRzaW5fZXJyW1s1XV18PiB1bmxpc3QoKSkgfD4gDQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KDQpkYXRhJGNvc19lcnJbNl0gPC0gbWVhbihkYXRhX3ByZXYkY29zX2VycltbNl1dfD4gdW5saXN0KCkpIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2Vycls2XSA8LSBtZWFuKGRhdGFfcHJldiRzaW5fZXJyW1s2XV18PiB1bmxpc3QoKSkgfD4gDQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCmZvciAoaSBpbiAxOjQpew0KICBmb3IgKGogaW4gKGkpOjQpew0KICAgIHggPC0gZGF0YV9wcmV2JGNvc19lcnJbW2ldXSB8PiB1bmxpc3QoKQ0KICAgIHkgPC0gZGF0YV9wcmV2JGNvc19lcnJbW2pdXSB8PiB1bmxpc3QoKQ0KICAgIHRfdGVzdF9yZXN1bHQgPC0gdC50ZXN0KHgsIHksIHBhaXJlZCA9IFRSVUUpDQogICAgcHJpbnQocGFzdGUoImNvcywgIiwgZGF0YSTQnNC10YLQvtC0W2ldLCAiICIsIGRhdGEk0JzQtdGC0L7QtFtqXSwgIiwgcC12YWwgPSAiLCB0X3Rlc3RfcmVzdWx0JHAudmFsdWUpKQ0KICB9DQp9DQoNCmZvciAoaSBpbiAxOjQpew0KICBmb3IgKGogaW4gKGkpOjQpew0KICAgIHggPC0gZGF0YV9wcmV2JHNpbl9lcnJbW2ldXSB8PiB1bmxpc3QoKQ0KICAgIHkgPC0gZGF0YV9wcmV2JHNpbl9lcnJbW2pdXSB8PiB1bmxpc3QoKQ0KICAgIHRfdGVzdF9yZXN1bHQgPC0gdC50ZXN0KHgsIHksIHBhaXJlZCA9IFRSVUUpDQogICAgcHJpbnQocGFzdGUoInNpbiwgIiwgZGF0YSTQnNC10YLQvtC0W2ldLCAiICIsIGRhdGEk0JzQtdGC0L7QtFtqXSwgIiwgcC12YWwgPSAiLCB0X3Rlc3RfcmVzdWx0JHAudmFsdWUpKQ0KICB9DQp9DQoNCg0KdGFibGVfbGF0ZXggPC0geHRhYmxlKGRhdGEsIGNhcHRpb24gPSAiRXhhbXBsZSBUYWJsZSIpDQoNCiMg0KjQsNCzIDQ6INCS0YvQstC+0LQg0YLQsNCx0LvQuNGG0Ysg0LIgTGFUZVgg0YTQsNC50LsNCnByaW50KHRhYmxlX2xhdGV4LCBpbmNsdWRlLnJvd25hbWVzID0gRkFMU0UpDQpgYGANCg0KIyMjIyDQlNC+0LHQsNCy0LjQvCDQvdC10L/QtdGA0LjQvtC00LjRh9C90L7RgdGC0YwNCg0KYGBge3J9DQpuIDwtIDk2KjINCnggPC0gMDoobi0xKQ0KTCA8LSA5Ng0KeTEgPC0gc2luKDIqcGkvMTIgKiB4KQ0KeTIgPC0gY29zKDIqcGkvMyAqIHgpLzINCnkzIDwtIGV4cCh4LzEwMCkgKyAxDQp5IDwtIHkxICsgeTIgKyB5Mw0KZXBzIDwtIDEvKG4rMSkNCg0Kc19zc2EgPC0gc3NhKHlbMToobi0xKV0sIEwpDQpyX3NzYSA8LSByZWNvbnN0cnVjdChzX3NzYSwgZ3JvdXBzPWxpc3QoDQogIGUgPSBjKDEpLA0KICBzZXNvbmFsX3NpbiA9IGMoMiwgMyksDQogIHNlc29uYWxfY29zID0gYyg0LCA1KQ0KKSkNCiMgcGxvdCh4WzE6KG4tMSldLCByX3NzYSRlLCB0eXBlID0gImwiKQ0KIyBwbG90KHhbMToobi0xKV0sIHJfc3NhJHNlc29uYWxfc2luLCB0eXBlID0gImwiKQ0KIyBwbG90KHhbMToobi0xKV0sIHJfc3NhJHNlc29uYWxfY29zLCB0eXBlID0gImwiKQ0KIyBwbG90KHdjb3Ioc19zc2EsIGdyb3VwcyA9IDE6MTApLCBzY2FsZXMgPSBsaXN0KGF0ID0gYygxMCwgMjAsIDMwKSkpDQplX3NzYSA8LSBlb3NzYV9uZXcoc19zc2EsIG5lc3RlZC5ncm91cHMgPSBsaXN0KDE6NyksIGNsdXN0X3R5cGUgPSAiZGlzdGFuY2UiKQ0KZ19zZXNvbmFsX2UgPC0gZ3JvdXBpbmcuYXV0byhlX3NzYSwgYmFzZSA9ICJlaWdlbiIsDQogICAgICAgICAgICAgICAgICAgICAgIGZyZXEuYmlucyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgICAgZSA9IGMoMCwgMS8xMi1lcHMtZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsX3NpbiA9IGMoMS8xMi1lcHMsIDEvMTIrZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsX2NvcyA9IGMoMS8zLWVwcywgMS8zK2VwcykNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgICAgICAgICAgICB0aHJlc2hvbGQgPSAwLjUpDQpyX3NzYV9lIDwtIHJlY29uc3RydWN0KGVfc3NhLCBncm91cHM9Z19zZXNvbmFsX2UpDQojIHBsb3QoeCwgcl9zc2FfZSRzZXNvbmFsX3NpbikNCiMgcGxvdCh4LCByX3NzYV9lJHNlc29uYWxfY29zKQ0KDQoNCg0Kcl9mZnQgPC0gcmVjb25zdHJ1Y3RfZmZ0KHgsIHkpDQpyX2ZmdF9ncm91cGVkIDwtIGdyb3VwaW5nX2Npc3NhKHJfZmZ0LA0KICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgIGUgPSBjKDAsIDEvMTItZXBzLWVwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMy1lcHMsIDEvMytlcHMpDQogICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0KDQpyX2ZmdF9leHRlbmRlZCA8LSByZWNvbnN0cnVjdF9mZnQoeCwgeSwgVFJVRSkNCnJfZmZ0X2dyb3VwZWRfZXh0ZW5kZWQgPC0gZ3JvdXBpbmdfY2lzc2Eocl9mZnRfZXh0ZW5kZWQsDQogICAgICAgICAgICAgICAgICAgIGdyb3VwcyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgZSA9IGMoMCwgMS8xMi1lcHMtZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsX3NpbiA9IGMoMS8xMi1lcHMsIDEvMTIrZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsX2NvcyA9IGMoMS8zLWVwcywgMS8zK2VwcykNCiAgICAgICAgICAgICAgICAgICAgKQ0KICAgICAgICAgICAgICAgICAgICApJHRfc2VyaWVzDQoNCiMgcl9mZnRfZ3JvdXBlZCRzZXNvbmFsX3NpbiB8PiBsZW5ndGgoKQ0KDQojIHBsb3QoeCwgcl9mZnRfZ3JvdXBlZCRzZXNvbmFsX3NpbikNCiMgcGxvdCh4LCByX2ZmdF9ncm91cGVkJHNlc29uYWxfY29zKQ0KIyBwbG90KHgsIHJfZmZ0X2dyb3VwZWQkcmVzaWR1YWxzKQ0KDQoNCnJfY2lzc2EgPC0gY2lyY3VsYW50X1NTQSh5LCBMKQ0Kcl9jaXNzYV9ncm91cGVkIDwtIGdyb3VwaW5nX2Npc3NhKHJfY2lzc2EsDQogICAgICAgICAgICAgICAgICAgIGdyb3VwcyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgZSA9IGMoMCwgMS8xMi1lcHMtZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsX3NpbiA9IGMoMS8xMi1lcHMsIDEvMTIrZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsX2NvcyA9IGMoMS8zLWVwcywgMS8zK2VwcykNCiAgICAgICAgICAgICAgICAgICAgKQ0KICAgICAgICAgICAgICAgICAgICApJHRfc2VyaWVzDQoNCg0Kcl9jaXNzYV9leHQgPC0gY2lyY3VsYW50X1NTQSh5LCBMLCBleHRlbmRfZmxhZyA9IFRSVUUpDQpyX2Npc3NhX2dyb3VwZWRfZXh0IDwtIGdyb3VwaW5nX2Npc3NhKHJfY2lzc2FfZXh0LA0KICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgIGUgPSBjKDAsIDEvMTItZXBzLWVwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMy1lcHMsIDEvMytlcHMpDQogICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0KDQojIHBsb3QoeCwgcl9jaXNzYV9ncm91cGVkJHNlc29uYWxfc2luKQ0KIyBwbG90KHgsIHJfY2lzc2FfZ3JvdXBlZCRzZXNvbmFsX2NvcykNCiMgcGxvdCh4LCByX2Npc3NhX2dyb3VwZWQkcmVzaWR1YWxzKQ0KDQpsaWJyYXJ5KHh0YWJsZSkNCg0KIyDQqNCw0LMgMjog0KHQvtC30LTQsNC90LjQtSDQv9GA0LjQvNC10YDQsCDQtNCw0L3QvdGL0YUNCmRhdGEgPC0gZGF0YS5mcmFtZSgNCiAg0JzQtdGC0L7QtCA9IGMoIlNTQSIsICJTU0EgRU9TU0EiLCJGb3VyaWVyIiwgIkNpU1NBIiwgIkNpU1NBIGV4dGVuZGVkIiwgIkZvdXJpZXIgZXh0ZW5kZWQiKSwNCiAgZV9lcnIgPSBjKDEsIDEsIDEsIDEsIDEsIDEpLA0KICBzaW5fZXJyID0gYyAoMSwgMjAsIDIwLCAxLCAxLCAxKSwNCiAgY29zX2VyciA9IGMoMSwgMSwgMSwgMSwgMSwgMSkNCikNCg0KZGF0YSRjb3NfZXJyWzFdIDwtIG1zZSh5MVsxOihuLTEpXSwgcl9zc2Ekc2Vzb25hbF9zaW4pIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRzaW5fZXJyWzFdIDwtIG1zZSh5MlsxOihuLTEpXSwgcl9zc2Ekc2Vzb25hbF9jb3MpIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRlX2VyclsxXSA8LSBtc2UoeTNbMToobi0xKV0sIHJfc3NhJGUpIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KDQpkYXRhJGNvc19lcnJbMl0gPC0gbXNlKHkxWzE6KG4tMSldLCByX3NzYV9lJHNlc29uYWxfc2luKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2VyclsyXSA8LSBtc2UoeTJbMToobi0xKV0sIHJfc3NhX2Ukc2Vzb25hbF9jb3MpIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRlX2VyclsyXSA8LSBtc2UoeTNbMToobi0xKV0sIHJfc3NhX2UkZSkgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQoNCg0KZGF0YSRjb3NfZXJyWzNdIDwtIG1zZSh5MSwgcl9mZnRfZ3JvdXBlZCRzZXNvbmFsX3NpbikgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJHNpbl9lcnJbM10gPC0gbXNlKHkyLCByX2ZmdF9ncm91cGVkJHNlc29uYWxfY29zKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkZV9lcnJbM10gPC0gbXNlKHkzLCByX2ZmdF9ncm91cGVkJGUpIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KDQoNCmRhdGEkY29zX2Vycls0XSA8LSBtc2UoeTEsIHJfY2lzc2FfZ3JvdXBlZCRzZXNvbmFsX3NpbikgfD4gDQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRzaW5fZXJyWzRdIDwtIG1zZSh5Miwgcl9jaXNzYV9ncm91cGVkJHNlc29uYWxfY29zKSB8PiANCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJGVfZXJyWzRdIDwtIG1zZSh5Mywgcl9jaXNzYV9ncm91cGVkJGUpIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KDQpkYXRhJGNvc19lcnJbNV0gPC0gbXNlKHkxLCByX2Npc3NhX2dyb3VwZWRfZXh0JHNlc29uYWxfc2luKSB8PiANCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJHNpbl9lcnJbNV0gPC0gbXNlKHkyLCByX2Npc3NhX2dyb3VwZWRfZXh0JHNlc29uYWxfY29zKSB8PiANCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJGVfZXJyWzVdIDwtIG1zZSh5Mywgcl9jaXNzYV9ncm91cGVkX2V4dCRlKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCg0KZGF0YSRjb3NfZXJyWzZdIDwtIG1zZSh5MSwgcl9mZnRfZ3JvdXBlZF9leHRlbmRlZCRzZXNvbmFsX3NpbikgfD4gDQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRzaW5fZXJyWzZdIDwtIG1zZSh5Miwgcl9mZnRfZ3JvdXBlZF9leHRlbmRlZCRzZXNvbmFsX2NvcykgfD4gDQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRlX2Vycls2XSA8LSBtc2UoeTMsIHJfZmZ0X2dyb3VwZWRfZXh0ZW5kZWQkZSkgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQoNCg0KDQp0YWJsZV9sYXRleCA8LSB4dGFibGUoZGF0YSwgY2FwdGlvbiA9ICJFeGFtcGxlIFRhYmxlIikNCg0KIyDQqNCw0LMgNDog0JLRi9Cy0L7QtCDRgtCw0LHQu9C40YbRiyDQsiBMYVRlWCDRhNCw0LnQuw0KcHJpbnQodGFibGVfbGF0ZXgsIGluY2x1ZGUucm93bmFtZXMgPSBGQUxTRSkNCmBgYA0KDQojIyMjINCd0LXQv9C10YDQuNC+0LTQuNGH0L3QvtGB0YLRjCDRgSDRiNGD0LzQvtC8DQoNCmBgYHtyfQ0KIyBkYXRhIDwtIGRhdGEuZnJhbWUoDQojICAg0JzQtdGC0L7QtCA9IGMoIkZvdXJpZXIiLCAiQ2lTU0EiLCAiQ2lTU0Eg0YEg0YDQsNGB0YjQuNGA0LXQvdC40LXQvCDRgNGP0LTQsCIpLA0KIyAgIHNpbl9lcnIgPSBjICgyMCwgMjAsIDIwKSwNCiMgICBjb3NfZXJyID0gYygxLCAxLCAyMCksDQojICAgZXhwX2VyciA9IGMoMSwgMSwgMjApDQojICkNCmRhdGEgPC0gbGlzdCgNCiAg0JzQtdGC0L7QtCA9IGMoIlNTQSIsICJTU0EgRU9TU0EiLCJGb3VyaWVyIiwgIkNpU1NBIiwgIkNpU1NBIGV4dGVuZGVkIiwgIkZvdXJpZXIgZXh0ZW5kZWQiKSwNCiAgc2luX2VyciA9IGxpc3QobGlzdCgpLCBsaXN0KCksIGxpc3QoKSwgbGlzdCgpLCBsaXN0KCksIGxpc3QoKSksDQogIGNvc19lcnIgPSBsaXN0KGxpc3QoKSwgbGlzdCgpLCBsaXN0KCksIGxpc3QoKSwgbGlzdCgpLCBsaXN0KCkpLA0KICBleHBfZXJyID0gbGlzdChsaXN0KCksIGxpc3QoKSwgbGlzdCgpLCBsaXN0KCksIGxpc3QoKSwgbGlzdCgpKQ0KKQ0KDQpmb3IgKGkgaW4gMToxMDApew0KICBzZXQuc2VlZChpKQ0KICANCiAgbiA8LSA5NioyDQogIHggPC0gMDoobi0xKQ0KICBMIDwtIDk2DQogIHkxIDwtIHNpbigyKnBpLzEyICogeCkNCiAgeTIgPC0gY29zKDIqcGkvMyAqIHgpLzINCiAgeTMgPC0gZXhwKHgvMTAwKSArIDENCiAgeSA8LSB5MSArIHkyICsgeTMgKyBybm9ybShuLCAwLCAwLjEpDQogIGVwcyA8LSAxLyhuKzEpDQogIA0KICBzX3NzYSA8LSBzc2EoeVsxOihuLTEpXSwgTCkNCiAgcl9zc2EgPC0gcmVjb25zdHJ1Y3Qoc19zc2EsIGdyb3Vwcz1saXN0KA0KICAgIGUgPSAxLA0KICAgIHNlc29uYWxfc2luID0gYygyLCAzKSwNCiAgICBzZXNvbmFsX2NvcyA9IGMoNCwgNSkNCiAgKSkNCiAgDQogIA0KICBlX3NzYSA8LSBlb3NzYV9uZXcoc19zc2EsIG5lc3RlZC5ncm91cHMgPSBsaXN0KDE6NiksIGNsdXN0X3R5cGUgPSAiZGlzdGFuY2UiKQ0KICBnX3Nlc29uYWxfZSA8LSBncm91cGluZy5hdXRvKGVfc3NhLCBiYXNlID0gImVpZ2VuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBmcmVxLmJpbnMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZSA9IGMoMCwgMS8xMi1lcHMtZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfc2luID0gYygxLzEyLWVwcywgMS8xMitlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMy1lcHMsIDEvMytlcHMpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHRocmVzaG9sZCA9IDAuNSkNCiAgcl9zc2FfZSA8LSByZWNvbnN0cnVjdChlX3NzYSwgZ3JvdXBzPWdfc2Vzb25hbF9lKQ0KICANCiAgDQogIA0KICByX2ZmdCA8LSByZWNvbnN0cnVjdF9mZnQoeCwgeSkNCiAgcl9mZnRfZ3JvdXBlZCA8LSBncm91cGluZ19jaXNzYShyX2ZmdCwNCiAgICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgZSA9IGMoMCwgMS8xMi1lcHMtZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfc2luID0gYygxLzEyLWVwcywgMS8xMitlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMy1lcHMsIDEvMytlcHMpDQogICAgICAgICAgICAgICAgICAgICAgKQ0KICAgICAgICAgICAgICAgICAgICAgICkkdF9zZXJpZXMNCiAgDQogIHJfZmZ0X2V4dGVuZGVkIDwtIHJlY29uc3RydWN0X2ZmdCh4LCB5LCBUUlVFKQ0KICByX2ZmdF9ncm91cGVkX2V4dGVuZGVkIDwtIGdyb3VwaW5nX2Npc3NhKHJfZmZ0X2V4dGVuZGVkLA0KICAgICAgICAgICAgICAgICAgICAgIGdyb3VwcyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgICBlID0gYygwLCAxLzEyLWVwcy1lcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgICBzZXNvbmFsX2NvcyA9IGMoMS8zLWVwcywgMS8zK2VwcykNCiAgICAgICAgICAgICAgICAgICAgICApDQogICAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0KICANCiAgDQogIHJfY2lzc2EgPC0gY2lyY3VsYW50X1NTQSh5LCBMKQ0KICByX2Npc3NhX2dyb3VwZWQgPC0gZ3JvdXBpbmdfY2lzc2Eocl9jaXNzYSwNCiAgICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgZSA9IGMoMCwgMS8xMi1lcHMtZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfc2luID0gYygxLzEyLWVwcywgMS8xMitlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMy1lcHMsIDEvMytlcHMpDQogICAgICAgICAgICAgICAgICAgICAgKQ0KICAgICAgICAgICAgICAgICAgICAgICkkdF9zZXJpZXMNCiAgDQogIA0KICByX2Npc3NhX2V4dCA8LSBjaXJjdWxhbnRfU1NBKHksIEwsIGV4dGVuZF9mbGFnID0gVFJVRSkNCiAgcl9jaXNzYV9ncm91cGVkX2V4dCA8LSBncm91cGluZ19jaXNzYShyX2Npc3NhX2V4dCwNCiAgICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgZSA9IGMoMCwgMS8xMi1lcHMtZXBzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfc2luID0gYygxLzEyLWVwcywgMS8xMitlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvMy1lcHMsIDEvMytlcHMpDQogICAgICAgICAgICAgICAgICAgICAgKQ0KICAgICAgICAgICAgICAgICAgICAgICkkdF9zZXJpZXMNCiAgDQogIA0KICANCiAgZGF0YSRjb3NfZXJyW1sxXV1bW2ldXSA8LSBtc2UoeTFbMToobi0xKV0sIHJfc3NhJHNlc29uYWxfc2luKQ0KICBkYXRhJHNpbl9lcnJbWzFdXVtbaV1dIDwtIG1zZSh5MlsxOihuLTEpXSwgcl9zc2Ekc2Vzb25hbF9jb3MpDQogIGRhdGEkZXhwX2VycltbMV1dW1tpXV0gPC0gbXNlKHkzWzE6KG4tMSldLCByX3NzYSRlKQ0KICANCiAgZGF0YSRjb3NfZXJyW1syXV1bW2ldXSA8LSBtc2UoeTFbMToobi0xKV0sIHJfc3NhX2Ukc2Vzb25hbF9zaW4pDQogIGRhdGEkc2luX2VycltbMl1dW1tpXV0gPC0gbXNlKHkyWzE6KG4tMSldLCByX3NzYV9lJHNlc29uYWxfY29zKQ0KICBkYXRhJGV4cF9lcnJbWzJdXVtbaV1dIDwtIG1zZSh5M1sxOihuLTEpXSwgcl9zc2FfZSRlKQ0KICANCiAgIyBwcmludChkYXRhJHNpbl9lcnJbWzJdXVtbaV1dKQ0KICANCiAgDQogIGRhdGEkY29zX2VycltbM11dW1tpXV0gPC0gbXNlKHkxLCByX2ZmdF9ncm91cGVkJHNlc29uYWxfc2luKQ0KICBkYXRhJHNpbl9lcnJbWzNdXVtbaV1dIDwtIG1zZSh5Miwgcl9mZnRfZ3JvdXBlZCRzZXNvbmFsX2NvcykNCiAgZGF0YSRleHBfZXJyW1szXV1bW2ldXSA8LSBtc2UoeTMsIHJfZmZ0X2dyb3VwZWQkZSkNCiAgDQogIA0KICBkYXRhJGNvc19lcnJbWzRdXVtbaV1dIDwtIG1zZSh5MSwgcl9jaXNzYV9ncm91cGVkJHNlc29uYWxfc2luKQ0KICBkYXRhJHNpbl9lcnJbWzRdXVtbaV1dIDwtIG1zZSh5Miwgcl9jaXNzYV9ncm91cGVkJHNlc29uYWxfY29zKQ0KICBkYXRhJGV4cF9lcnJbWzRdXVtbaV1dIDwtIG1zZSh5Mywgcl9jaXNzYV9ncm91cGVkJGUpDQogIA0KICANCiAgZGF0YSRjb3NfZXJyW1s1XV1bW2ldXSA8LSBtc2UoeTEsIHJfY2lzc2FfZ3JvdXBlZF9leHQkc2Vzb25hbF9zaW4pDQogIGRhdGEkc2luX2VycltbNV1dW1tpXV0gPC0gbXNlKHkyLCByX2Npc3NhX2dyb3VwZWRfZXh0JHNlc29uYWxfY29zKQ0KICBkYXRhJGV4cF9lcnJbWzVdXVtbaV1dIDwtIG1zZSh5Mywgcl9jaXNzYV9ncm91cGVkX2V4dCRlKQ0KICANCiAgZGF0YSRjb3NfZXJyW1s2XV1bW2ldXSA8LSBtc2UoeTEsIHJfZmZ0X2dyb3VwZWRfZXh0ZW5kZWQkc2Vzb25hbF9zaW4pDQogIGRhdGEkc2luX2VycltbNl1dW1tpXV0gPC0gbXNlKHkyLCByX2ZmdF9ncm91cGVkX2V4dGVuZGVkJHNlc29uYWxfY29zKQ0KICBkYXRhJGV4cF9lcnJbWzZdXVtbaV1dIDwtIG1zZSh5Mywgcl9mZnRfZ3JvdXBlZF9leHRlbmRlZCRlKQ0KfQ0KbGlicmFyeSh4dGFibGUpDQojIGRhdGEkc2luX2VycltbMl1dDQojINCo0LDQsyAyOiDQodC+0LfQtNCw0L3QuNC1INC/0YDQuNC80LXRgNCwINC00LDQvdC90YvRhQ0KZGF0YV9wcmV2IDwtIGRhdGENCmRhdGEgPC0gZGF0YS5mcmFtZSgNCiAg0JzQtdGC0L7QtCA9IGMoIlNTQSIsICJTU0EgRU9TU0EiLCJGb3VyaWVyIiwgIkNpU1NBIiwgIkNpU1NBIGV4dGVuZGVkIiwgIkZvdXJpZXIgZXh0ZW5kZWQiKSwNCiAgc2luX2VyciA9IGMoMCwgMCwgMCwgMCwgMCwgMCksDQogIGNvc19lcnIgPSBjKDAsIDAsIDAsIDAsIDAsIDApLA0KICBleHBfZXJyID0gYygwLCAwLCAwLCAwLCAwLCAwKQ0KKQ0KDQpkYXRhJGNvc19lcnJbMV0gPC0gbWVhbihkYXRhX3ByZXYkY29zX2VycltbMV1dIHw+IHVubGlzdCgpKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2VyclsxXSA8LSBtZWFuKGRhdGFfcHJldiRzaW5fZXJyW1sxXV18PiB1bmxpc3QoKSkgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJGV4cF9lcnJbMV0gPC0gbWVhbihkYXRhX3ByZXYkZXhwX2VycltbMV1dfD4gdW5saXN0KCkpIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KDQoNCmRhdGEkY29zX2VyclsyXSA8LSBtZWFuKGRhdGFfcHJldiRjb3NfZXJyW1syXV18PiB1bmxpc3QoKSkgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJHNpbl9lcnJbMl0gPC0gbWVhbihkYXRhX3ByZXYkc2luX2VycltbMl1dfD4gdW5saXN0KCkpIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRleHBfZXJyWzJdIDwtIG1lYW4oZGF0YV9wcmV2JGV4cF9lcnJbWzJdXXw+IHVubGlzdCgpKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCg0KDQpkYXRhJGNvc19lcnJbM10gPC0gbWVhbihkYXRhX3ByZXYkY29zX2VycltbM11dfD4gdW5saXN0KCkpIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2VyclszXSA8LSBtZWFuKGRhdGFfcHJldiRzaW5fZXJyW1szXV18PiB1bmxpc3QoKSkgfD4gDQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRleHBfZXJyWzNdIDwtIG1lYW4oZGF0YV9wcmV2JGV4cF9lcnJbWzNdXXw+IHVubGlzdCgpKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCg0KDQpkYXRhJGNvc19lcnJbNF0gPC0gbWVhbihkYXRhX3ByZXYkY29zX2VycltbNF1dfD4gdW5saXN0KCkpIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2Vycls0XSA8LSBtZWFuKGRhdGFfcHJldiRzaW5fZXJyW1s0XV18PiB1bmxpc3QoKSkgfD4gDQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRleHBfZXJyWzRdIDwtIG1lYW4oZGF0YV9wcmV2JGV4cF9lcnJbWzRdXXw+IHVubGlzdCgpKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCg0KZGF0YSRjb3NfZXJyWzVdIDwtIG1lYW4oZGF0YV9wcmV2JGNvc19lcnJbWzVdXXw+IHVubGlzdCgpKSB8PiANCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJHNpbl9lcnJbNV0gPC0gbWVhbihkYXRhX3ByZXYkc2luX2VycltbNV1dfD4gdW5saXN0KCkpIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkZXhwX2Vycls1XSA8LSBtZWFuKGRhdGFfcHJldiRleHBfZXJyW1s1XV18PiB1bmxpc3QoKSkgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQoNCmRhdGEkY29zX2Vycls2XSA8LSBtZWFuKGRhdGFfcHJldiRjb3NfZXJyW1s2XV18PiB1bmxpc3QoKSkgfD4gDQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRzaW5fZXJyWzZdIDwtIG1lYW4oZGF0YV9wcmV2JHNpbl9lcnJbWzZdXXw+IHVubGlzdCgpKSB8PiANCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJGV4cF9lcnJbNl0gPC0gbWVhbihkYXRhX3ByZXYkZXhwX2VycltbNl1dfD4gdW5saXN0KCkpIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCmZvciAoaSBpbiAxOjQpew0KICBmb3IgKGogaW4gKGkpOjQpew0KICAgIHggPC0gZGF0YV9wcmV2JGNvc19lcnJbW2ldXSB8PiB1bmxpc3QoKQ0KICAgIHkgPC0gZGF0YV9wcmV2JGNvc19lcnJbW2pdXSB8PiB1bmxpc3QoKQ0KICAgIHRfdGVzdF9yZXN1bHQgPC0gdC50ZXN0KHgsIHksIHBhaXJlZCA9IFRSVUUpDQogICAgcHJpbnQocGFzdGUoImNvcywgIiwgZGF0YSTQnNC10YLQvtC0W2ldLCAiICIsIGRhdGEk0JzQtdGC0L7QtFtqXSwgIiwgcC12YWwgPSAiLCB0X3Rlc3RfcmVzdWx0JHAudmFsdWUpKQ0KICB9DQp9DQoNCmZvciAoaSBpbiAxOjQpew0KICBmb3IgKGogaW4gKGkpOjQpew0KICAgIHggPC0gZGF0YV9wcmV2JHNpbl9lcnJbW2ldXSB8PiB1bmxpc3QoKQ0KICAgIHkgPC0gZGF0YV9wcmV2JHNpbl9lcnJbW2pdXSB8PiB1bmxpc3QoKQ0KICAgIHRfdGVzdF9yZXN1bHQgPC0gdC50ZXN0KHgsIHksIHBhaXJlZCA9IFRSVUUpDQogICAgcHJpbnQocGFzdGUoInNpbiwgIiwgZGF0YSTQnNC10YLQvtC0W2ldLCAiICIsIGRhdGEk0JzQtdGC0L7QtFtqXSwgIiwgcC12YWwgPSAiLCB0X3Rlc3RfcmVzdWx0JHAudmFsdWUpKQ0KICB9DQp9DQoNCmZvciAoaSBpbiAxOjQpew0KICBmb3IgKGogaW4gKGkpOjQpew0KICAgIHggPC0gZGF0YV9wcmV2JGV4cF9lcnJbW2ldXSB8PiB1bmxpc3QoKQ0KICAgIHkgPC0gZGF0YV9wcmV2JGV4cF9lcnJbW2pdXSB8PiB1bmxpc3QoKQ0KICAgIHRfdGVzdF9yZXN1bHQgPC0gdC50ZXN0KHgsIHksIHBhaXJlZCA9IFRSVUUpDQogICAgcHJpbnQocGFzdGUoImV4cCwgIiwgZGF0YSTQnNC10YLQvtC0W2ldLCAiICIsIGRhdGEk0JzQtdGC0L7QtFtqXSwgIiwgcC12YWwgPSAiLCB0X3Rlc3RfcmVzdWx0JHAudmFsdWUpKQ0KICB9DQp9DQoNCg0KdGFibGVfbGF0ZXggPC0geHRhYmxlKGRhdGEsIGNhcHRpb24gPSAiRXhhbXBsZSBUYWJsZSIpDQoNCiMg0KjQsNCzIDQ6INCS0YvQstC+0LQg0YLQsNCx0LvQuNGG0Ysg0LIgTGFUZVgg0YTQsNC50LsNCnByaW50KHRhYmxlX2xhdGV4LCBpbmNsdWRlLnJvd25hbWVzID0gRkFMU0UpDQpgYGANCg0KIyMjIyDQn9GA0LjQvNC10YAsINC60L7RgtC+0YDRi9C5INC90LUg0L/QvtC00YXQvtC00LjRgiDQvdC4INC6INC60LDQutC+0LzRgyDQvNC10YLQvtC00YMNCg0KYGBge3J9DQpuIDwtIDk2KjIgKyA3DQpMIDwtIDg5DQp4IDwtIDA6KG4tMSkNCnkxIDwtIHNpbigyKnBpLzEzICogeCkNCnkyIDwtIGNvcygyKnBpLzggKiB4KQ0KeTMgPC0gLXgqeC8xMDAwDQp5NCA8LSBleHAoeC81NSkNCnkgPC0geTEgKyB5MiArIHkzICsgeTQgDQpwbG90KHgsIHkpDQpYIDwtIGhhbmtlbCh5LCBMID0gTCkNCmVwcyA8LSAxLyhuKzEpDQoNCnNfc3NhIDwtIHNzYSh5LCBMKQ0KIyByX3NzYSA8LSByZWNvbnN0cnVjdChzX3NzYSwgZ3JvdXBzPWxpc3QoDQojICAgc2Vzb25hbF9zaW4gPSBjKDEsIDIpLA0KIyAgIHNlc29uYWxfY29zID0gYygzLCA0KQ0KIyApKQ0KIyBwbG90KHgsIHJfc3NhJHNlc29uYWxfc2luKQ0KIyBwbG90KHgsIHJfc3NhJHNlc29uYWxfY29zKQ0KIyBwbG90KHdjb3Ioc19zc2EsIGdyb3VwcyA9IDE6MTApLCBzY2FsZXMgPSBsaXN0KGF0ID0gYygxMCwgMjAsIDMwKSkpDQplX3NzYSA8LSBlb3NzYV9uZXcoc19zc2EsIG5lc3RlZC5ncm91cHMgPSBsaXN0KDE6MTApLCBjbHVzdF90eXBlID0gImRpc3RhbmNlIikNCmdfc2Vzb25hbF9lIDwtIGdyb3VwaW5nLmF1dG8oZV9zc2EsIGJhc2UgPSAiZWlnZW4iLA0KICAgICAgICAgICAgICAgICAgICAgICBmcmVxLmJpbnMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfc2luID0gYygxLzEyLWVwcywgMS8xMitlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfY29zID0gYygxLzgtZXBzLCAxLzgrZXBzKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICAgICAgICAgIHRocmVzaG9sZCA9IDAuNSkNCnJfc3NhX2UgPC0gcmVjb25zdHJ1Y3QoZV9zc2EsIGdyb3Vwcz1nX3Nlc29uYWxfZSkNCiMgcGxvdCh4LCByX3NzYV9lJHNlc29uYWxfc2luKQ0KIyBwbG90KHgsIHJfc3NhX2Ukc2Vzb25hbF9jb3MpDQoNCg0KDQpyX2ZmdCA8LSByZWNvbnN0cnVjdF9mZnQoeCwgeSkNCnJfZmZ0X2dyb3VwZWQgPC0gZ3JvdXBpbmdfY2lzc2Eocl9mZnQsDQogICAgICAgICAgICAgICAgICAgIGdyb3VwcyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvOC1lcHMsIDEvOCtlcHMpDQogICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0KDQojIHJfZmZ0X2dyb3VwZWQkc2Vzb25hbF9zaW4gfD4gbGVuZ3RoKCkNCg0KIyBwbG90KHgsIHJfZmZ0X2dyb3VwZWQkc2Vzb25hbF9zaW4pDQojIHBsb3QoeCwgcl9mZnRfZ3JvdXBlZCRzZXNvbmFsX2NvcykNCiMgcGxvdCh4LCByX2ZmdF9ncm91cGVkJHJlc2lkdWFscykNCg0KDQpyX2Npc3NhIDwtIGNpcmN1bGFudF9TU0EoeSwgTCkNCnJfY2lzc2FfZ3JvdXBlZCA8LSBncm91cGluZ19jaXNzYShyX2Npc3NhLA0KICAgICAgICAgICAgICAgICAgICBncm91cHMgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfc2luID0gYygxLzEyLWVwcywgMS8xMitlcHMpLA0KICAgICAgICAgICAgICAgICAgICAgIHNlc29uYWxfY29zID0gYygxLzgtZXBzLCAxLzgrZXBzKQ0KICAgICAgICAgICAgICAgICAgICApDQogICAgICAgICAgICAgICAgICAgICkkdF9zZXJpZXMNCg0KDQpyX2Npc3NhX2V4dCA8LSBjaXJjdWxhbnRfU1NBKHksIEwsIGV4dGVuZF9mbGFnID0gVFJVRSkNCnJfY2lzc2FfZ3JvdXBlZF9leHQgPC0gZ3JvdXBpbmdfY2lzc2Eocl9jaXNzYV9leHQsDQogICAgICAgICAgICAgICAgICAgIGdyb3VwcyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9zaW4gPSBjKDEvMTItZXBzLCAxLzEyK2VwcyksDQogICAgICAgICAgICAgICAgICAgICAgc2Vzb25hbF9jb3MgPSBjKDEvOC1lcHMsIDEvOCtlcHMpDQogICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICAgICAgKSR0X3Nlcmllcw0KDQojIHBsb3QoeCwgcl9jaXNzYV9ncm91cGVkJHNlc29uYWxfc2luKQ0KIyBwbG90KHgsIHJfY2lzc2FfZ3JvdXBlZCRzZXNvbmFsX2NvcykNCiMgcGxvdCh4LCByX2Npc3NhX2dyb3VwZWQkcmVzaWR1YWxzKQ0KDQpsaWJyYXJ5KHh0YWJsZSkNCg0KIyDQqNCw0LMgMjog0KHQvtC30LTQsNC90LjQtSDQv9GA0LjQvNC10YDQsCDQtNCw0L3QvdGL0YUNCmRhdGEgPC0gZGF0YS5mcmFtZSgNCiAg0JzQtdGC0L7QtCA9IGMoIlNTQSBFT1NTQSIsIkZvdXJpZXIiLCAiQ2lTU0EiLCAiQ2lTU0EgZXh0ZW5kZWQiKSwNCiAgc2luX2VyciA9IGMgKDIwLCAyMCwgMSwgMSksDQogIGNvc19lcnIgPSBjKDEsIDEsIDEsIDEpDQopDQoNCmRhdGEkY29zX2VyclsxXSA8LSBtc2UoeTEsIHJfc3NhX2Ukc2Vzb25hbF9zaW4pIHw+DQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KZGF0YSRzaW5fZXJyWzFdIDwtIG1zZSh5Miwgcl9zc2FfZSRzZXNvbmFsX2NvcykgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQoNCg0KZGF0YSRjb3NfZXJyWzJdIDwtIG1zZSh5MSwgcl9mZnRfZ3JvdXBlZCRzZXNvbmFsX3NpbikgfD4NCiAgZm9ybWF0Qyhmb3JtYXQgPSAiZSIsIGRpZ2l0cyA9IDEpDQpkYXRhJHNpbl9lcnJbMl0gPC0gbXNlKHkyLCByX2ZmdF9ncm91cGVkJHNlc29uYWxfY29zKSB8Pg0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCg0KDQpkYXRhJGNvc19lcnJbM10gPC0gbXNlKHkxLCByX2Npc3NhX2dyb3VwZWQkc2Vzb25hbF9zaW4pIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2VyclszXSA8LSBtc2UoeTIsIHJfY2lzc2FfZ3JvdXBlZCRzZXNvbmFsX2NvcykgfD4gDQogIGZvcm1hdEMoZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAxKQ0KDQoNCmRhdGEkY29zX2Vycls0XSA8LSBtc2UoeTEsIHJfY2lzc2FfZ3JvdXBlZF9leHQkc2Vzb25hbF9zaW4pIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCmRhdGEkc2luX2Vycls0XSA8LSBtc2UoeTIsIHJfY2lzc2FfZ3JvdXBlZF9leHQkc2Vzb25hbF9jb3MpIHw+IA0KICBmb3JtYXRDKGZvcm1hdCA9ICJlIiwgZGlnaXRzID0gMSkNCg0KDQoNCnRhYmxlX2xhdGV4IDwtIHh0YWJsZShkYXRhLCBjYXB0aW9uID0gIkV4YW1wbGUgVGFibGUiKQ0KDQojINCo0LDQsyA0OiDQktGL0LLQvtC0INGC0LDQsdC70LjRhtGLINCyIExhVGVYINGE0LDQudC7DQpwcmludCh0YWJsZV9sYXRleCwgaW5jbHVkZS5yb3duYW1lcyA9IEZBTFNFKQ0KYGBgDQo=